Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #2778 UI : Add Queries tab for table details page. #2793

Merged
merged 13 commits into from
Feb 19, 2022
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import SchemaEditor from '../schema-editor/SchemaEditor';
import SchemaTab from '../SchemaTab/SchemaTab.component';
import TableProfiler from '../TableProfiler/TableProfiler.component';
import TableProfilerGraph from '../TableProfiler/TableProfilerGraph.component';
import TableQueries from '../TableQueries/TableQueries';
import { DatasetDetailsProps } from './DatasetDetails.interface';

const DatasetDetails: React.FC<DatasetDetailsProps> = ({
Expand Down Expand Up @@ -85,6 +86,8 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
entityLineageHandler,
isLineageLoading,
isSampleDataLoading,
isQueriesLoading,
tableQueries,
}: DatasetDetailsProps) => {
const { isAuthDisabled } = useAuth();
const [isEdit, setIsEdit] = useState(false);
Expand Down Expand Up @@ -150,6 +153,17 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
isProtected: false,
position: 2,
},
{
name: 'Queries',
icon: {
alt: 'table_queries',
name: 'table_queries',
title: 'Table Queries',
selectedName: '',
},
isProtected: false,
position: 3,
},
{
name: 'Profiler',
icon: {
Expand All @@ -159,7 +173,7 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
selectedName: 'icon-profilercolor',
},
isProtected: false,
position: 3,
position: 4,
},
{
name: 'Lineage',
Expand All @@ -170,7 +184,7 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
selectedName: 'icon-lineagecolor',
},
isProtected: false,
position: 4,
position: 5,
},
{
name: 'DBT',
Expand All @@ -182,7 +196,7 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
},
isProtected: false,
isHidden: !dataModel?.sql,
position: 5,
position: 6,
},
{
name: 'Manage',
Expand All @@ -195,7 +209,7 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
isProtected: true,
isHidden: deleted,
protectedState: !owner || hasEditAccess(),
position: 6,
position: 7,
},
];

Expand Down Expand Up @@ -471,6 +485,14 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
</div>
)}
{activeTab === 3 && (
<div>
<TableQueries
isLoading={isQueriesLoading}
queries={tableQueries}
/>
</div>
)}
{activeTab === 4 && (
<div>
<TableProfiler
columns={columns.map((col) => ({
Expand All @@ -481,7 +503,7 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
/>
</div>
)}
{activeTab === 4 && (
{activeTab === 5 && (
<div
className={classNames(
location.pathname.includes(ROUTES.TOUR)
Expand All @@ -503,7 +525,7 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
/>
</div>
)}
{activeTab === 5 && Boolean(dataModel?.sql) && (
{activeTab === 6 && 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"
Expand All @@ -512,7 +534,7 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
/>
</div>
)}
{activeTab === 6 && !deleted && (
{activeTab === 7 && !deleted && (
<div>
<ManageTab
currentTier={tier?.tagFQN}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export interface DatasetDetailsProps {
owner: DatasetOwner;
description: string;
tableProfile: Table['tableProfile'];
tableQueries: Table['tableQueries'];
columns: Table['columns'];
tier: TagLabel;
sampleData: TableData;
Expand All @@ -54,6 +55,7 @@ export interface DatasetDetailsProps {
deleted?: boolean;
isLineageLoading?: boolean;
isSampleDataLoading?: boolean;
isQueriesLoading?: boolean;
setActiveTabHandler: (value: number) => void;
followTableHandler: () => void;
unfollowTableHandler: () => void;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ const DatasetDetailsProps = {
addLineageHandler: jest.fn(),
removeLineageHandler: jest.fn(),
entityLineageHandler: jest.fn(),
tableQueries: [],
};
jest.mock('../ManageTab/ManageTab.component', () => {
return jest.fn().mockReturnValue(<p>ManageTab</p>);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
* Copyright 2021 Collate
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import classNames from 'classnames';
import React, { FC, HTMLAttributes, useState } from 'react';
import CopyToClipboard from 'react-copy-to-clipboard';
import { CSMode } from '../../enums/codemirror.enum';
import { SQLQuery, Table } from '../../generated/entity/data/table';
import { withLoader } from '../../hoc/withLoader';
import SVGIcons, { Icons } from '../../utils/SvgUtils';
import { Button } from '../buttons/Button/Button';
import SchemaEditor from '../schema-editor/SchemaEditor';

interface TableQueriesProp extends HTMLAttributes<HTMLDivElement> {
queries: Table['tableQueries'];
}
interface QueryCardProp extends HTMLAttributes<HTMLDivElement> {
query: SQLQuery;
}

const QueryCard: FC<QueryCardProp> = ({ className, query }) => {
const [expanded, setExpanded] = useState<boolean>(false);
const [, setIsCopied] = useState<boolean>(false);
const [showCopiedText, setShowCopiedText] = useState<boolean>(false);

const copiedTextHandler = () => {
setShowCopiedText(true);
setTimeout(() => {
setShowCopiedText(false);
}, 1000);
};

return (
<div className={classNames('tw-bg-white tw-py-3 tw-mb-3', className)}>
<div
className="tw-cursor-pointer"
onClick={() => setExpanded((pre) => !pre)}>
<div className="tw-flex tw-py-1 tw-justify-between">
<p>
Last run by{' '}
<span className="tw-font-medium">
{query.user?.displayName ?? query.user?.name}
</span>{' '}
and took{' '}
<span className="tw-font-medium">{query.duration} seconds</span>
</p>

<button>
{expanded ? (
<SVGIcons
alt="copy"
className="tw-mr-4"
icon={Icons.ICON_UP}
width="16px"
/>
) : (
<SVGIcons
alt="copy"
className="tw-mr-4"
icon={Icons.ICON_DOWN}
width="16px"
/>
)}
</button>
</div>
</div>
<div className="tw-border tw-border-main tw-rounded-md tw-p-px">
<div
className={classNames('tw-overflow-hidden tw-relative', {
'tw-max-h-10': !expanded,
})}>
<CopyToClipboard
text={query.query ?? ''}
onCopy={(_text, result) => {
setIsCopied(result);
if (result) copiedTextHandler();
}}>
<Button
className="tw-h-8 tw-ml-4 tw-absolute tw-right-4 tw-z-9999 tw--mt-px"
data-testid="copy-query"
size="custom"
theme="default"
title="Copy"
variant="text">
{showCopiedText ? (
<span className="tw-mr-1 tw-text-success tw-bg-success-lite tw-px-1 tw-rounded-md">
Copied!
</span>
) : null}
<SVGIcons alt="copy" icon={Icons.COPY} width="16px" />
</Button>
</CopyToClipboard>

<SchemaEditor
editorClass={classNames('table-query-editor')}
mode={{ name: CSMode.SQL }}
options={{
styleActiveLine: false,
}}
value={query.query ?? ''}
/>
</div>
</div>
</div>
);
};

const TableQueries: FC<TableQueriesProp> = ({ queries, className }) => {
return (
<div className={className}>
<div className="tw-my-6">
{queries?.map((query, index) => (
<QueryCard key={index} query={query} />
))}
</div>
</div>
);
};

export default withLoader<TableQueriesProp>(TableQueries);
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const PopOver: React.FC<PopOverProp> = ({
title,
trigger,
theme = 'dark',
sticky = false,
}): JSX.Element => {
return (
<Tooltip
Expand All @@ -39,6 +40,7 @@ const PopOver: React.FC<PopOverProp> = ({
html={html}
position={position}
size={size}
sticky={sticky}
theme={theme}
title={title || ''}
trigger={trigger}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ export type PopOverProp = {
className?: string;
delay?: number;
hideDelay?: number;
sticky?: boolean;
};
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,18 @@ const SchemaEditor = ({
name: CSMode.JAVASCRIPT,
json: true,
},
options,
editorClass,
}: {
value: string;
className?: string;
mode?: Mode;
options?: {
[key: string]: string | boolean | Array<string>;
};
editorClass?: string;
}) => {
const options = {
const defaultOptions = {
tabSize: JSON_TAB_SIZE,
indentUnit: JSON_TAB_SIZE,
indentWithTabs: false,
Expand All @@ -57,6 +63,7 @@ const SchemaEditor = ({
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
mode,
readOnly: true,
...options,
};
const [internalValue, setInternalValue] = useState(
getSchemaEditorValue(value)
Expand All @@ -72,7 +79,8 @@ const SchemaEditor = ({
return (
<div className={className}>
<CodeMirror
options={options}
className={editorClass}
options={defaultOptions}
value={internalValue}
onBeforeChange={handleEditorInputBeforeChange}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,5 @@ export enum TabSpecificField {
DATAMODEL = 'dataModel',
CHARTS = 'charts',
TASKS = 'tasks',
TABLE_QUERIES = 'tableQueries',
}