Skip to content

Commit

Permalink
ui: Add user guide link for table sampling feature (#1460)
Browse files Browse the repository at this point in the history
* ui: Add user guide link for table sampling feature
  • Loading branch information
zhangvi7 committed Jun 19, 2024
1 parent 731a166 commit 054774f
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 17 deletions.
1 change: 1 addition & 0 deletions querybook/config/querybook_public_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ table_sampling:
sample_rates:
- 0.1
default_sample_rate: 0 # 0 means no sampling
sample_user_guide_link: ''
33 changes: 26 additions & 7 deletions querybook/webapp/components/DataDocQueryCell/DataDocQueryCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { connect } from 'react-redux';

import { AICommandBar } from 'components/AIAssistant/AICommandBar';
import { DataDocQueryExecutions } from 'components/DataDocQueryExecutions/DataDocQueryExecutions';
import { DataDocTableSamplingInfo } from 'components/DataDocTableSamplingInfo/DataDocTableSamplingInfo';
import { QueryCellTitle } from 'components/QueryCellTitle/QueryCellTitle';
import { runQuery, transformQuery } from 'components/QueryComposer/RunQuery';
import { BoundQueryEditor } from 'components/QueryEditor/BoundQueryEditor';
Expand Down Expand Up @@ -45,12 +46,7 @@ import {
import { DEFAULT_ROW_LIMIT } from 'lib/sql-helper/sql-limiter';
import { getPossibleTranspilers } from 'lib/templated-query/transpile';
import { enableResizable } from 'lib/utils';
import {
getShortcutSymbols,
KeyMap,
matchKeyMap,
matchKeyPress,
} from 'lib/utils/keyboard';
import { getShortcutSymbols, KeyMap, matchKeyPress } from 'lib/utils/keyboard';
import { doesLanguageSupportUDF } from 'lib/utils/udf';
import * as dataDocActions from 'redux/dataDoc/action';
import * as dataSourcesActions from 'redux/dataSources/action';
Expand Down Expand Up @@ -126,6 +122,7 @@ interface IState {
hasLintError: boolean;
tableNamesInQuery: string[];
samplingTables: ISamplingTables;
showTableSamplingInfoModal: boolean;

transpilerConfig?: {
toEngine: IQueryEngine;
Expand Down Expand Up @@ -154,6 +151,7 @@ class DataDocQueryCellComponent extends React.PureComponent<IProps, IState> {
hasLintError: false,
tableNamesInQuery: [],
samplingTables: {},
showTableSamplingInfoModal: false,
};
}

Expand Down Expand Up @@ -225,7 +223,7 @@ class DataDocQueryCellComponent extends React.PureComponent<IProps, IState> {
}

public get hasSamplingTables() {
return Object.keys(this.samplingTables).length > 0;
return Object.keys(this.state.samplingTables).length > 0;
}

public get sampleRate() {
Expand Down Expand Up @@ -686,6 +684,13 @@ class DataDocQueryCellComponent extends React.PureComponent<IProps, IState> {
}));
}

@bind
public toggleShowTableSamplingInfoModal() {
this.setState(({ showTableSamplingInfoModal }) => ({
showTableSamplingInfoModal: !showTableSamplingInfoModal,
}));
}

@bind
public fetchDataTableByNameIfNeeded(schema: string, table: string) {
return this.props.fetchDataTableByNameIfNeeded(
Expand Down Expand Up @@ -804,6 +809,9 @@ class DataDocQueryCellComponent extends React.PureComponent<IProps, IState> {
? this.handleMetaSampleRateChange
: null
}
onTableSamplingInfoClick={
this.toggleShowTableSamplingInfoModal
}
/>
{this.getAdditionalDropDownButtonDOM()}
</div>
Expand Down Expand Up @@ -937,13 +945,24 @@ class DataDocQueryCellComponent extends React.PureComponent<IProps, IState> {
/>
) : null;

const renderTableSamplingInfoDOM = this.state
.showTableSamplingInfoModal && (
<DataDocTableSamplingInfo
query={this.state.query}
language={this.queryEngine.language}
samplingTables={this.samplingTables}
onHide={this.toggleShowTableSamplingInfoModal}
/>
);

return (
<>
{editorDOM}
{insertQuerySnippetModalDOM}
{templatedQueryViewModalDOM}
{UDFModal}
{transpilerModal}
{renderTableSamplingInfoDOM}
</>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.DataDocTableSamplingInfo {
.link-text-highlight {
color: var(--color-accent-dark);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React from 'react';

import { QueryComparison } from 'components/TranspileQueryModal/QueryComparison';
import PublicConfig from 'config/querybook_public_config.yaml';
import { ISamplingTables } from 'const/datadoc';
import { useResource } from 'hooks/useResource';
import { formatError } from 'lib/utils/error';
import { QueryTransformResource } from 'resource/queryTransform';
import { Link } from 'ui/Link/Link';
import { Loading } from 'ui/Loading/Loading';
import { ErrorMessage } from 'ui/Message/ErrorMessage';
import { Modal } from 'ui/Modal/Modal';

import './DataDocTableSamplingInfo.scss';

interface IProps {
query: string;
language: string;
samplingTables: ISamplingTables;
onHide: () => void;
}

export const DataDocTableSamplingInfo: React.FC<IProps> = ({
query,
language,
samplingTables,
onHide,
}) => {
const sampleUserGuideLink =
PublicConfig.table_sampling?.sample_user_guide_link ?? '';

const {
data: sampledQuery,
isLoading,
isError,
error,
} = useResource(
React.useCallback(
() =>
QueryTransformResource.getSampledQuery(
query,
language,
samplingTables
),
[language, query, samplingTables]
)
);

let contentDOM = null;

if (isLoading) {
contentDOM = <Loading />;
} else if (isError) {
contentDOM = (
<ErrorMessage title={'Failed to sample query.'}>
{formatError(error)}
</ErrorMessage>
);
} else {
contentDOM = (
<Modal onHide={onHide}>
<div className="DataDocTableSamplingInfo">
By enabling table sampling, it will use a sample version of
the table or apply table sample to the original table.
{sampleUserGuideLink ? (
<span>
{' '}
Please see more about it{' '}
<Link to={sampleUserGuideLink} newTab>
<span className="link-text-highlight">
here
</span>
</Link>
</span>
) : null}
</div>
<QueryComparison
fromQuery={query}
toQuery={sampledQuery}
fromQueryTitle={'Original Query'}
toQueryTitle={'Transformed Query'}
/>
</Modal>
);
}
return contentDOM;
};
18 changes: 18 additions & 0 deletions querybook/webapp/components/QueryComposer/QueryComposer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import React, {
import toast from 'react-hot-toast';
import { useDispatch, useSelector } from 'react-redux';

import { DataDocTableSamplingInfo } from 'components/DataDocTableSamplingInfo/DataDocTableSamplingInfo';
import { DataDocTemplateInfoButton } from 'components/DataDocTemplateButton/DataDocTemplateInfoButton';
import { DataDocTemplateVarForm } from 'components/DataDocTemplateButton/DataDocTemplateVarForm';
import { detectVariableType } from 'components/DataDocTemplateButton/helpers';
Expand Down Expand Up @@ -439,6 +440,9 @@ const QueryComposer: React.FC = () => {

const [hasLintErrors, setHasLintErrors] = useState(false);

const [showTableSamplingInfoModal, setShowTableSamplingInfoModal] =
useState(false);

const runButtonRef = useRef<IQueryRunButtonHandles>(null);
const clickOnRunButton = useCallback(() => {
if (runButtonRef.current) {
Expand Down Expand Up @@ -500,6 +504,7 @@ const QueryComposer: React.FC = () => {
element: ElementType.RUN_QUERY_BUTTON,
aux: {
lintError: hasLintErrors,
sampleRate,
},
});
// Throttle to prevent double run
Expand Down Expand Up @@ -657,6 +662,15 @@ const QueryComposer: React.FC = () => {
</Modal>
);

const renderTableSamplingInfoDOM = showTableSamplingInfoModal && (
<DataDocTableSamplingInfo
query={getCurrentSelectedQuery()}
language={engine.language}
samplingTables={samplingTables}
onHide={() => setShowRenderedTemplateModal(false)}
/>
);

const queryEditorWrapperClassname = clsx({
'query-editor-wrapper': true,
mb16: executionId != null,
Expand All @@ -674,6 +688,7 @@ const QueryComposer: React.FC = () => {
</div>
{executionDOM()}
{udfModalDOM}
{renderTableSamplingInfoDOM}
</div>
);

Expand All @@ -693,6 +708,9 @@ const QueryComposer: React.FC = () => {
hasSamplingTables={Object.keys(samplingTables).length > 0}
sampleRate={sampleRate}
onSampleRateChange={setSampleRate}
onTableSamplingInfoClick={() =>
setShowTableSamplingInfoModal(true)
}
/>
</div>
);
Expand Down
38 changes: 28 additions & 10 deletions querybook/webapp/components/QueryRunButton/QueryRunButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { stopPropagation } from 'lib/utils/noop';
import { formatNumber } from 'lib/utils/number';
import { queryEngineStatusByIdEnvSelector } from 'redux/queryEngine/selector';
import { AsyncButton, IAsyncButtonHandles } from 'ui/AsyncButton/AsyncButton';
import { IconButton } from 'ui/Button/IconButton';
import { Dropdown } from 'ui/Dropdown/Dropdown';
import { Icon } from 'ui/Icon/Icon';
import { ListMenu } from 'ui/Menu/ListMenu';
Expand All @@ -43,6 +44,7 @@ interface IQueryRunButtonProps extends IQueryEngineSelectorProps {
hasSamplingTables?: boolean;
sampleRate?: number;
onSampleRateChange?: (sampleRate: number) => void;
onTableSamplingInfoClick?: () => void;
}

export interface IQueryRunButtonHandles {
Expand All @@ -69,6 +71,7 @@ export const QueryRunButton = React.forwardRef<
hasSamplingTables,
sampleRate,
onSampleRateChange,
onTableSamplingInfoClick,
},
ref
) => {
Expand Down Expand Up @@ -108,6 +111,7 @@ export const QueryRunButton = React.forwardRef<
sampleRate={sampleRate}
setSampleRate={onSampleRateChange}
tooltipPos={runButtonTooltipPos}
onTableSamplingInfoClick={onTableSamplingInfoClick}
/>
) : null;

Expand Down Expand Up @@ -285,7 +289,8 @@ const TableSamplingSelector: React.FC<{
sampleRate: number;
setSampleRate: (sampleRate: number) => void;
tooltipPos: TooltipDirection;
}> = ({ sampleRate, setSampleRate, tooltipPos }) => {
onTableSamplingInfoClick: () => void;
}> = ({ sampleRate, setSampleRate, tooltipPos, onTableSamplingInfoClick }) => {
React.useEffect(() => {
if (!sampleRateOptions.some((option) => option.value === sampleRate)) {
setSampleRate(DEFAULT_SAMPLE_RATE);
Expand All @@ -308,15 +313,28 @@ const TableSamplingSelector: React.FC<{
return (
<Dropdown
customButtonRenderer={() => (
<div
className="flex-center ph4"
aria-label="Only applies to tables support sampling"
data-balloon-pos={tooltipPos}
>
<span className="mr4">
Sample: {selectedSampleRateText}
</span>
<Icon name="ChevronDown" size={24} color="light" />
<div className="flex-row">
<div
className="flex-center"
aria-label="Click to see how table sampling works"
data-balloon-pos={tooltipPos}
>
<IconButton
icon="Info"
size={20}
onClick={onTableSamplingInfoClick}
/>
</div>
<div
className="flex-center"
aria-label="Only applies to tables support sampling"
data-balloon-pos={tooltipPos}
>
<span className="mr4">
Sample: {selectedSampleRateText}
</span>
<Icon name="ChevronDown" size={24} color="light" />
</div>
</div>
)}
layout={['bottom', 'right']}
Expand Down
1 change: 1 addition & 0 deletions querybook/webapp/config.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ declare module 'config/querybook_public_config.yaml' {
enabled: boolean;
sample_rates: Array<number>;
default_sample_rate: number;
sample_user_guide_link: string;
};
};
export default data;
Expand Down

0 comments on commit 054774f

Please sign in to comment.