Unverified Commit c3b77880 authored by Tamika Tannis's avatar Tamika Tannis Committed by GitHub

Preview feature fixes (#16)

* Reset preview reducer state on GetTableData

* Fix type error

* preview state should be controlled by tableMetadata reducer

* dispatch getPreviewData from TableDetail container

* Pass a modalTitle to DataPreviewButton instead of queryParams
parent edc1d199
......@@ -3,7 +3,7 @@ import * as React from 'react';
import { Button, Modal, OverlayTrigger, Popover, Table } from 'react-bootstrap';
import Linkify from 'react-linkify'
import { PreviewData, PreviewQueryParams } from '../types';
import { PreviewData } from '../types';
// TODO: Use css-modules instead of 'import'
import './styles.scss';
......@@ -22,15 +22,11 @@ export interface StateFromProps {
status: LoadingStatus;
}
export interface DispatchFromProps {
getPreviewData: (queryParams: PreviewQueryParams) => void;
}
export interface ComponentProps {
queryParams: PreviewQueryParams;
modalTitle: string;
}
type DataPreviewButtonProps = StateFromProps & DispatchFromProps & ComponentProps;
type DataPreviewButtonProps = StateFromProps & ComponentProps;
interface DataPreviewButtonState {
status: LoadingStatus;
......@@ -94,10 +90,6 @@ class DataPreviewButton extends React.Component<DataPreviewButtonProps, DataPrev
return value || '';
}
componentDidMount() {
this.props.getPreviewData(this.props.queryParams);
}
renderModalBody() {
const previewData = this.state.previewData;
......@@ -201,14 +193,6 @@ class DataPreviewButton extends React.Component<DataPreviewButtonProps, DataPrev
return previewButton;
}
/*
TODO: Propose redesign of this UI. Original design has tooltip with error
messages appear when hovering over the button, but:
1. BootStrap popover has 'flickering' issues, potential upgrade to 4.0 could fix?
2. Designs for a few other features use an 'info' button to indicate that there
is discoverable help text, why not use that here.
*/
// when button is disabled, render button with Popover
const popoverHover = (
<Popover id="popover-trigger-hover">
......@@ -237,7 +221,7 @@ class DataPreviewButton extends React.Component<DataPreviewButtonProps, DataPrev
<Modal show={this.state.showModal} onHide={this.handleClose}>
<Modal.Header className="text-center" closeButton={true}>
<Modal.Title>
{`${this.props.queryParams.schema}.${this.props.queryParams.tableName}`}
{this.props.modalTitle}
</Modal.Title>
</Modal.Header>
<Modal.Body>
......
......@@ -23,7 +23,7 @@ import Avatar from 'react-avatar';
import { OverlayTrigger, Popover } from 'react-bootstrap';
import { RouteComponentProps } from 'react-router';
import { TableMetadata } from './types';
import { PreviewQueryParams, TableMetadata } from './types';
// TODO: Use css-modules instead of 'import'
import './styles.scss';
......@@ -36,6 +36,7 @@ export interface StateFromProps {
export interface DispatchFromProps {
getTableData: (cluster: string, database: string, schema: string, tableName: string, searchIndex?: string, source?: string, ) => GetTableDataRequest;
getPreviewData: (queryParams: PreviewQueryParams) => void;
}
type TableDetailProps = StateFromProps & DispatchFromProps;
......@@ -53,6 +54,7 @@ class TableDetail extends React.Component<TableDetailProps & RouteComponentProps
private tableName: string;
public static defaultProps: TableDetailProps = {
getTableData: () => undefined,
getPreviewData: () => undefined,
isLoading: true,
statusCode: null,
tableData: {} as TableMetadata,
......@@ -91,6 +93,7 @@ class TableDetail extends React.Component<TableDetailProps & RouteComponentProps
}
this.props.getTableData(this.cluster, this.database, this.schema, this.tableName, searchIndex, source);
this.props.getPreviewData({ schema: this.schema, tableName: this.tableName });
}
getAvatarForUser(fullName, profileUrl) {
......@@ -246,7 +249,7 @@ class TableDetail extends React.Component<TableDetailProps & RouteComponentProps
const previewSectionRenderer = () => {
return (
<div>
<DataPreviewButton queryParams={{'schema': data.schema, 'tableName': data.table_name}} />
<DataPreviewButton modalTitle={`${data.schema}.${data.tableName}`} />
{
AppConfig.tableProfile.isExploreEnabled &&
<a role="button" href={this.getExploreSqlUrl()} target="_blank" className="btn btn-primary btn-block">
......
......@@ -2,19 +2,14 @@ import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { GlobalState } from "../../../ducks/rootReducer";
import { getPreviewData } from '../../../ducks/preview/reducer';
import DataPreviewButton, { ComponentProps, DispatchFromProps, StateFromProps, getStatusFromCode } from '../../../components/TableDetail/DataPreviewButton';
import DataPreviewButton, { ComponentProps, StateFromProps, getStatusFromCode } from '../../../components/TableDetail/DataPreviewButton';
export const mapStateToProps = (state: GlobalState) => {
return {
previewData: state.preview.previewData,
status: getStatusFromCode(state.preview.status),
previewData: state.tableMetadata.preview.data,
status: getStatusFromCode(state.tableMetadata.preview.status),
};
};
export const mapDispatchToProps = (dispatch: any) => {
return bindActionCreators({ getPreviewData } , dispatch);
};
export default connect<StateFromProps, DispatchFromProps, ComponentProps>(mapStateToProps, mapDispatchToProps)(DataPreviewButton);
export default connect<StateFromProps, {}, ComponentProps>(mapStateToProps, null)(DataPreviewButton);
......@@ -2,7 +2,7 @@ import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { GlobalState } from "../../ducks/rootReducer";
import { getTableData } from '../../ducks/tableMetadata/reducer';
import { getPreviewData, getTableData } from '../../ducks/tableMetadata/reducer';
import TableDetail, { DispatchFromProps, StateFromProps } from '../../components/TableDetail';
......@@ -15,7 +15,7 @@ export const mapStateToProps = (state: GlobalState) => {
};
export const mapDispatchToProps = (dispatch: any) => {
return bindActionCreators({ getTableData } , dispatch);
return bindActionCreators({ getPreviewData, getTableData } , dispatch);
};
export default connect<StateFromProps, DispatchFromProps>(mapStateToProps, mapDispatchToProps)(TableDetail);
import axios from 'axios';
import { GetPreviewDataRequest } from '../../tableMetadata/reducer';
const API_PATH = '/api/metadata/v0';
const sortTagsAlphabetical = (a, b) => a.tag_name.localeCompare(b.tag_name);
......@@ -140,9 +142,22 @@ export function metadataUpdateColumnDescription(description, columnIndex, tableD
}
}
export function metadataGetLastIndexed() {
return axios.get(`${API_PATH}/get_last_indexed`).then((response) => {
return response.data.timestamp;
});
}
export function metadataGetPreviewData(action: GetPreviewDataRequest) {
return axios({
url: '/api/preview/v0/',
method: 'POST',
data: action.queryParams,
})
.then((response) => {
return { data: response.data.previewData, status: response.status };
})
.catch((error) => {
return { data: error.response.data.previewData, status: error.response.status };
});
}
import axios from 'axios';
import { GetPreviewDataRequest } from '../../preview/reducer';
export function getPreviewData(action: GetPreviewDataRequest) {
return axios({
url: '/api/preview/v0/',
method: 'POST',
data: action.queryParams,
})
.then((response) => {
return { previewData: response.data.previewData, status: response.status };
})
.catch((error) => {
return { previewData: error.response.data.previewData, status: error.response.status };
});
}
import { PreviewData, PreviewQueryParams } from '../../components/TableDetail/types';
/* getPreviewData */
export enum GetPreviewData {
ACTION = 'amundsen/preview/GET_PREVIEW_DATA',
SUCCESS = 'amundsen/preview/GET_PREVIEW_DATA_SUCCESS',
FAILURE = 'amundsen/preview/GET_PREVIEW_DATA_FAILURE',
}
export interface GetPreviewDataRequest {
type: GetPreviewData.ACTION;
queryParams: PreviewQueryParams;
}
interface GetPreviewDataResponse {
type: GetPreviewData.SUCCESS | GetPreviewData.FAILURE;
payload: PreviewDataReducerState;
}
export function getPreviewData(queryParams: PreviewQueryParams): GetPreviewDataRequest {
return { queryParams, type: GetPreviewData.ACTION };
}
/* end getPreviewData */
export type PreviewDataReducerAction = GetPreviewDataRequest | GetPreviewDataResponse;
export type PreviewDataReducerState = {
previewData: PreviewData;
status: number;
}
const initialState: PreviewDataReducerState = {
previewData: {},
status: null,
};
export default function reducer(state: PreviewDataReducerState = initialState, action: PreviewDataReducerAction): PreviewDataReducerState {
switch (action.type) {
case GetPreviewData.SUCCESS:
case GetPreviewData.FAILURE:
return action.payload;
default:
return state;
}
}
import { call, put, takeEvery } from 'redux-saga/effects';
import { SagaIterator } from 'redux-saga';
import {
GetPreviewData,
GetPreviewDataRequest,
} from './reducer';
import {
getPreviewData,
} from '../api/preview/v0';
export function* getPreviewDataWorker(action: GetPreviewDataRequest): SagaIterator {
let response;
try {
response = yield call(getPreviewData, action);
yield put({ type: GetPreviewData.SUCCESS, payload: response });
} catch (e) {
yield put({ type: GetPreviewData.FAILURE, payload: response });
}
}
export function* getPreviewDataWatcher(): SagaIterator {
yield takeEvery(GetPreviewData.ACTION, getPreviewDataWorker);
}
......@@ -3,7 +3,6 @@ import { combineReducers } from 'redux';
import announcements, { AnnouncementsReducerState } from './announcements/reducer';
import feedback, { FeedbackReducerState } from './feedback/reducer';
import popularTables, { PopularTablesReducerState } from './popularTables/reducer';
import preview, { PreviewDataReducerState } from './preview/reducer';
import search, { SearchReducerState } from './search/reducer';
import tableMetadata, { TableMetadataReducerState } from './tableMetadata/reducer';
import tags, { TagReducerState } from './tags/reducer';
......@@ -13,7 +12,6 @@ export interface GlobalState {
announcements: AnnouncementsReducerState;
feedback: FeedbackReducerState;
popularTables: PopularTablesReducerState;
preview: PreviewDataReducerState;
search: SearchReducerState;
tableMetadata: TableMetadataReducerState;
tags: TagReducerState;
......@@ -24,7 +22,6 @@ export default combineReducers<GlobalState>({
announcements,
feedback,
popularTables,
preview,
search,
tableMetadata,
tags,
......
......@@ -3,9 +3,6 @@ import { all } from 'redux-saga/effects';
// AnnouncementPage
import { announcementsGetWatcher } from "./announcements/sagas";
// DataPreviewButton
import { getPreviewDataWatcher } from './preview/sagas';
// FeedbackForm
import { submitFeedbackWatcher } from './feedback/sagas';
......@@ -18,6 +15,7 @@ import {
getTableDataWatcher,
getColumnDescriptionWatcher,
getLastIndexedWatcher,
getPreviewDataWatcher,
getTableDescriptionWatcher,
updateColumnDescriptionWatcher,
updateTableDescriptionWatcher,
......@@ -35,8 +33,6 @@ export default function* rootSaga() {
yield all([
// AnnouncementPage
announcementsGetWatcher(),
// DataPreviewButton
getPreviewDataWatcher(),
// FeedbackForm
submitFeedbackWatcher(),
// SearchPage
......@@ -49,6 +45,7 @@ export default function* rootSaga() {
getTableDataWatcher(),
getColumnDescriptionWatcher(),
getLastIndexedWatcher(),
getPreviewDataWatcher(),
getTableDescriptionWatcher(),
updateColumnDescriptionWatcher(),
updateTableDescriptionWatcher(),
......
import { TableMetadata } from '../../components/TableDetail/types';
import { PreviewData, PreviewQueryParams, TableMetadata } from '../../components/TableDetail/types';
import { UpdateTagData } from '../../components/Tags/types';
/* getTableData */
......@@ -230,9 +230,32 @@ interface GetLastIndexedResponse {
export function getLastIndexed(): GetLastIndexedRequest {
return { type: GetLastIndexed.ACTION };
}
/* end getLastIndexed */
/* getPreviewData */
export enum GetPreviewData {
ACTION = 'amundsen/preview/GET_PREVIEW_DATA',
SUCCESS = 'amundsen/preview/GET_PREVIEW_DATA_SUCCESS',
FAILURE = 'amundsen/preview/GET_PREVIEW_DATA_FAILURE',
}
interface PreviewDataState {
data: PreviewData;
status: number | null;
}
export interface GetPreviewDataRequest {
type: GetPreviewData.ACTION;
queryParams: PreviewQueryParams;
}
interface GetPreviewDataResponse {
type: GetPreviewData.SUCCESS | GetPreviewData.FAILURE;
payload: PreviewDataState;
}
export function getPreviewData(queryParams: PreviewQueryParams): GetPreviewDataRequest {
return { queryParams, type: GetPreviewData.ACTION };
}
/* end getPreviewData */
export type TableMetadataReducerAction =
GetTableDataRequest | GetTableDataResponse |
GetTableDescriptionRequest | GetTableDescriptionResponse |
......@@ -241,28 +264,35 @@ export type TableMetadataReducerAction =
GetColumnDescriptionRequest | GetColumnDescriptionResponse |
UpdateColumnDescriptionRequest | UpdateColumnDescriptionResponse |
UpdateTagsRequest | UpdateTagsResponse |
GetLastIndexedRequest | GetLastIndexedResponse;
GetLastIndexedRequest | GetLastIndexedResponse |
GetPreviewDataRequest | GetPreviewDataResponse;
export interface TableMetadataReducerState {
isLoading: boolean;
isLoadingTags: boolean;
lastIndexed: number;
preview: PreviewDataState;
statusCode: number;
tableData: TableMetadata;
lastIndexed: number;
}
const initialPreviewState = {
data: {},
status: null,
};
const initialState: TableMetadataReducerState = {
isLoading: true,
isLoadingTags: true,
lastIndexed: null,
preview: initialPreviewState,
statusCode: null,
tableData: {} as TableMetadata,
lastIndexed: null,
};
export default function reducer(state: TableMetadataReducerState = initialState, action: TableMetadataReducerAction): TableMetadataReducerState {
switch (action.type) {
case GetTableData.ACTION:
return { ...state, isLoading: true, isLoadingTags: true };
return { ...state, isLoading: true, isLoadingTags: true, preview: initialPreviewState };
case GetTableData.FAILURE:
case GetTableData.SUCCESS:
return { ...state, isLoading: false, isLoadingTags: false, statusCode: action.payload.statusCode, tableData: action.payload.tableData };
......@@ -276,6 +306,9 @@ export default function reducer(state: TableMetadataReducerState = initialState,
return { ...state, lastIndexed: action.payload };
case GetLastIndexed.FAILURE:
return { ...state, lastIndexed: null };
case GetPreviewData.SUCCESS:
case GetPreviewData.FAILURE:
return { ...state, preview: action.payload };
case UpdateTags.FAILURE:
return { ...state, isLoadingTags: false };
case UpdateTags.SUCCESS:
......
......@@ -2,33 +2,28 @@ import { all, call, put, select, takeEvery } from 'redux-saga/effects';
import { SagaIterator } from 'redux-saga';
import {
GetTableData,
GetTableDataRequest,
GetTableDescription,
GetTableDescriptionRequest,
UpdateTableDescription,
UpdateTableDescriptionRequest,
UpdateTableOwner,
UpdateTableOwnerRequest,
GetColumnDescription,
GetColumnDescriptionRequest,
UpdateColumnDescription,
UpdateColumnDescriptionRequest,
UpdateTags,
UpdateTagsRequest,
GetLastIndexedRequest, GetLastIndexed,
GetPreviewData, GetPreviewDataRequest,
GetTableData, GetTableDataRequest,
GetColumnDescription, GetColumnDescriptionRequest,
GetTableDescription, GetTableDescriptionRequest,
UpdateColumnDescription, UpdateColumnDescriptionRequest,
UpdateTableDescription, UpdateTableDescriptionRequest,
UpdateTableOwner, UpdateTableOwnerRequest,
UpdateTags, UpdateTagsRequest,
} from './reducer';
import {
metadataGetLastIndexed,
metadataGetPreviewData,
metadataGetTableData,
metadataGetColumnDescription,
metadataGetTableDescription,
metadataUpdateColumnDescription,
metadataUpdateTableDescription,
metadataUpdateTableOwner,
metadataGetColumnDescription,
metadataUpdateColumnDescription,
metadataTableTags,
metadataUpdateTableTags,
metadataGetLastIndexed,
metadataTableTags,
} from '../api/metadata/v0';
// getTableData
......@@ -178,3 +173,18 @@ export function* getLastIndexedWorker(action: GetLastIndexedRequest): SagaIterat
export function* getLastIndexedWatcher(): SagaIterator {
yield takeEvery(GetLastIndexed.ACTION, getLastIndexedWorker)
}
// getPreviewData
export function* getPreviewDataWorker(action: GetPreviewDataRequest): SagaIterator {
let response;
try {
response = yield call(metadataGetPreviewData, action);
yield put({ type: GetPreviewData.SUCCESS, payload: response });
} catch (e) {
yield put({ type: GetPreviewData.FAILURE, payload: response });
}
}
export function* getPreviewDataWatcher(): SagaIterator {
yield takeEvery(GetPreviewData.ACTION, getPreviewDataWorker);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment