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

Reorganize table owners & table tags state (#30)

* Un-nest owners and tags state: Move from state.tableMetadata.tableData to state.tableMetadata

* Create a nested reducer for owners

* Rename ducks/tags -> ducks/allTags to reduce confusion with table tags

* Create a nested reducer for table tags

* Some code cleanup

* Added table data defaults + utilMethods
parent 3bbb6c9e
...@@ -7,7 +7,7 @@ import AppConfig from '../../../config/config'; ...@@ -7,7 +7,7 @@ import AppConfig from '../../../config/config';
import LoadingSpinner from '../common/LoadingSpinner'; import LoadingSpinner from '../common/LoadingSpinner';
import TagInfo from "../Tags/TagInfo"; import TagInfo from "../Tags/TagInfo";
import { Tag } from "../Tags/types"; import { Tag } from "../Tags/types";
import { GetAllTagsRequest } from "../../ducks/tags/reducer"; import { GetAllTagsRequest } from "../../ducks/allTags/reducer";
export interface StateFromProps { export interface StateFromProps {
allTags: Tag[]; allTags: Tag[];
......
...@@ -23,7 +23,7 @@ import Avatar from 'react-avatar'; ...@@ -23,7 +23,7 @@ import Avatar from 'react-avatar';
import { OverlayTrigger, Popover } from 'react-bootstrap'; import { OverlayTrigger, Popover } from 'react-bootstrap';
import { RouteComponentProps } from 'react-router'; import { RouteComponentProps } from 'react-router';
import { PreviewQueryParams, TableMetadata } from './types'; import { PreviewQueryParams, TableMetadata, TableOwners } from './types';
// TODO: Use css-modules instead of 'import' // TODO: Use css-modules instead of 'import'
import './styles.scss'; import './styles.scss';
...@@ -32,6 +32,7 @@ export interface StateFromProps { ...@@ -32,6 +32,7 @@ export interface StateFromProps {
isLoading: boolean; isLoading: boolean;
statusCode?: number; statusCode?: number;
tableData: TableMetadata; tableData: TableMetadata;
tableOwners: TableOwners;
} }
export interface DispatchFromProps { export interface DispatchFromProps {
...@@ -45,6 +46,7 @@ interface TableDetailState { ...@@ -45,6 +46,7 @@ interface TableDetailState {
isLoading: boolean; isLoading: boolean;
statusCode: number; statusCode: number;
tableData: TableMetadata; tableData: TableMetadata;
tableOwners: TableOwners;
} }
class TableDetail extends React.Component<TableDetailProps & RouteComponentProps<any>, TableDetailState> { class TableDetail extends React.Component<TableDetailProps & RouteComponentProps<any>, TableDetailState> {
...@@ -57,12 +59,27 @@ class TableDetail extends React.Component<TableDetailProps & RouteComponentProps ...@@ -57,12 +59,27 @@ class TableDetail extends React.Component<TableDetailProps & RouteComponentProps
getPreviewData: () => undefined, getPreviewData: () => undefined,
isLoading: true, isLoading: true,
statusCode: null, statusCode: null,
tableData: {} as TableMetadata, tableData: {
columns: [],
is_editable: false,
schema: '',
table_name: '',
table_description: '',
table_writer: { application_url: '', description: '', id: '', name: '' },
partition: { is_partitioned: false },
table_readers: [],
source: { source: '', source_type: '' },
watermarks: [],
},
tableOwners: {
isLoading: true,
owners: [],
},
}; };
static getDerivedStateFromProps(nextProps, prevState) { static getDerivedStateFromProps(nextProps, prevState) {
const { isLoading, statusCode, tableData} = nextProps; const { isLoading, statusCode, tableData, tableOwners } = nextProps;
return { isLoading, statusCode, tableData }; return { isLoading, statusCode, tableData, tableOwners };
} }
constructor(props) { constructor(props) {
...@@ -79,6 +96,7 @@ class TableDetail extends React.Component<TableDetailProps & RouteComponentProps ...@@ -79,6 +96,7 @@ class TableDetail extends React.Component<TableDetailProps & RouteComponentProps
isLoading: props.isLoading, isLoading: props.isLoading,
statusCode: props.statusCode, statusCode: props.statusCode,
tableData: props.tableData, tableData: props.tableData,
tableOwners: props.tableOwners,
} }
} }
...@@ -173,14 +191,17 @@ class TableDetail extends React.Component<TableDetailProps & RouteComponentProps ...@@ -173,14 +191,17 @@ class TableDetail extends React.Component<TableDetailProps & RouteComponentProps
return AppConfig.tableProfile.exploreUrlGenerator(this.database, this.cluster, this.schema, this.tableName); return AppConfig.tableProfile.exploreUrlGenerator(this.database, this.cluster, this.schema, this.tableName);
}; };
createEntityCardSections(data) { createEntityCardSections = () => {
const data = this.state.tableData;
const tableOwners = this.state.tableOwners;
const entityCardSections = []; const entityCardSections = [];
// "Owned By" section // "Owned By" section
const listItemRenderer = (props) => { const listItemRenderer = (props) => {
return React.createElement(AvatarLabel, {label: props.label}); return React.createElement(AvatarLabel, {label: props.label});
}; };
const listItemProps = data.owners.map((entry) => { const listItemProps = tableOwners.owners.map((entry) => {
return { label: entry.display_name }; return { label: entry.display_name };
}); });
const listItemPropTypes = [{name:'email', property: 'label', type: 'text'}]; const listItemPropTypes = [{name:'email', property: 'label', type: 'text'}];
...@@ -307,7 +328,7 @@ class TableDetail extends React.Component<TableDetailProps & RouteComponentProps ...@@ -307,7 +328,7 @@ class TableDetail extends React.Component<TableDetailProps & RouteComponentProps
/> />
</div> </div>
<div className="col-xs-12 col-md-5 float-md-right col-lg-4"> <div className="col-xs-12 col-md-5 float-md-right col-lg-4">
<EntityCard sections={ this.createEntityCardSections(data) }/> <EntityCard sections={ this.createEntityCardSections() }/>
</div> </div>
<div className="detail-list-header col-xs-12 col-md-7 col-lg-8"> <div className="detail-list-header col-xs-12 col-md-7 col-lg-8">
<label>Columns</label> <label>Columns</label>
......
...@@ -26,7 +26,12 @@ interface TableColumnStats { ...@@ -26,7 +26,12 @@ interface TableColumnStats {
interface TableReader { interface TableReader {
read_count: number; read_count: number;
reader: User[]; reader: User;
}
interface TableSource {
source: string | null;
source_type: string;
} }
interface TableWriter { interface TableWriter {
...@@ -36,8 +41,9 @@ interface TableWriter { ...@@ -36,8 +41,9 @@ interface TableWriter {
name: string; name: string;
} }
interface User { export interface User {
display_name: string; display_name: string;
profile_url: string;
} }
export interface PreviewQueryParams { export interface PreviewQueryParams {
...@@ -59,6 +65,11 @@ export interface TableColumn { ...@@ -59,6 +65,11 @@ export interface TableColumn {
stats: TableColumnStats[]; stats: TableColumnStats[];
} }
export interface TableOwners {
isLoading: boolean;
owners: User[];
}
export interface TableMetadata { export interface TableMetadata {
columns: TableColumn[]; columns: TableColumn[];
is_editable: boolean; is_editable: boolean;
...@@ -66,10 +77,9 @@ export interface TableMetadata { ...@@ -66,10 +77,9 @@ export interface TableMetadata {
table_name: string; table_name: string;
table_description: string; table_description: string;
table_writer: TableWriter; table_writer: TableWriter;
owners: User[];
partition: PartitionData; partition: PartitionData;
table_readers: TableReader[]; table_readers: TableReader[];
tags: Tag[]; source: TableSource;
watermarks: Watermark[]; watermarks: Watermark[];
} }
......
...@@ -6,8 +6,8 @@ import Select, { components } from 'react-select'; ...@@ -6,8 +6,8 @@ import Select, { components } from 'react-select';
import CreatableSelect from 'react-select/lib/Creatable'; import CreatableSelect from 'react-select/lib/Creatable';
import makeAnimated from 'react-select/lib/animated'; import makeAnimated from 'react-select/lib/animated';
import { GetAllTagsRequest } from '../../../ducks/tags/reducer'; import { GetAllTagsRequest } from '../../../ducks/allTags/reducer';
import { UpdateTagsRequest } from '../../../ducks/tableMetadata/reducer'; import { UpdateTagsRequest } from '../../../ducks/tableMetadata/tags/reducer';
import TagInfo from "../TagInfo"; import TagInfo from "../TagInfo";
import { Tag, UpdateTagMethod, UpdateTagData } from '../types'; import { Tag, UpdateTagMethod, UpdateTagData } from '../types';
......
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'; import { bindActionCreators } from 'redux';
import { getAllTags } from '../../ducks/tags/reducer'; import { getAllTags } from '../../ducks/allTags/reducer';
import BrowsePage, { DispatchFromProps, StateFromProps } from '../../components/BrowsePage'; import BrowsePage, { DispatchFromProps, StateFromProps } from '../../components/BrowsePage';
import { GlobalState } from "../../ducks/rootReducer"; import { GlobalState } from "../../ducks/rootReducer";
export const mapStateToProps = (state: GlobalState) => { export const mapStateToProps = (state: GlobalState) => {
return { return {
allTags: state.tags.allTags, allTags: state.allTags.allTags,
isLoading: state.tags.isLoading, isLoading: state.allTags.isLoading,
}; };
}; };
......
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'; import { bindActionCreators } from 'redux';
import { updateTableOwner, UpdateMethod } from '../../../ducks/tableMetadata/reducer'; import { updateTableOwner, UpdateMethod } from '../../../ducks/tableMetadata/owners/reducer';
import EditableList, { ComponentProps, DispatchFromProps } from '../../../components/common/EditableList'; import EditableList, { ComponentProps, DispatchFromProps } from '../../../components/common/EditableList';
......
...@@ -11,6 +11,7 @@ export const mapStateToProps = (state: GlobalState) => { ...@@ -11,6 +11,7 @@ export const mapStateToProps = (state: GlobalState) => {
isLoading: state.tableMetadata.isLoading, isLoading: state.tableMetadata.isLoading,
statusCode: state.tableMetadata.statusCode, statusCode: state.tableMetadata.statusCode,
tableData: state.tableMetadata.tableData, tableData: state.tableMetadata.tableData,
tableOwners: state.tableMetadata.tableOwners,
}; };
}; };
......
...@@ -2,16 +2,16 @@ import { connect } from 'react-redux'; ...@@ -2,16 +2,16 @@ import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'; import { bindActionCreators } from 'redux';
import { GlobalState } from "../../ducks/rootReducer"; import { GlobalState } from "../../ducks/rootReducer";
import { getAllTags } from '../../ducks/tags/reducer'; import { getAllTags } from '../../ducks/allTags/reducer';
import { updateTags } from '../../ducks/tableMetadata/reducer'; import { updateTags } from '../../ducks/tableMetadata/tags/reducer';
import TagInput, { ComponentProps, DispatchFromProps, StateFromProps} from '../../components/Tags/TagInput'; import TagInput, { ComponentProps, DispatchFromProps, StateFromProps} from '../../components/Tags/TagInput';
export const mapStateToProps = (state: GlobalState) => { export const mapStateToProps = (state: GlobalState) => {
return { return {
allTags: state.tags.allTags, allTags: state.allTags.allTags,
isLoading: state.tags.isLoading || state.tableMetadata.isLoadingTags, isLoading: state.allTags.isLoading || state.tableMetadata.tableTags.isLoading,
tags: state.tableMetadata.tableData.tags, tags: state.tableMetadata.tableTags.tags,
}; };
}; };
......
import axios from 'axios';
import { sortTagsAlphabetical } from '../../utilMethods';
export function metadataAllTags() {
return axios.get('/api/metadata/v0/tags').then((response) => {
return response.data.tags.sort(sortTagsAlphabetical);
})
.catch((error) => {
return error.response.data.tags.sort(sortTagsAlphabetical);
});
}
...@@ -2,9 +2,9 @@ import { Tag } from '../../components/Tags/types'; ...@@ -2,9 +2,9 @@ import { Tag } from '../../components/Tags/types';
/* getAllTags */ /* getAllTags */
export enum GetAllTags { export enum GetAllTags {
ACTION = 'amundsen/tags/GET_ALL_TAGS', ACTION = 'amundsen/allTags/GET_ALL_TAGS',
SUCCESS = 'amundsen/tags/GET_ALL_TAGS_SUCCESS', SUCCESS = 'amundsen/allTags/GET_ALL_TAGS_SUCCESS',
FAILURE = 'amundsen/tags/GET_ALL_TAGS_FAILURE', FAILURE = 'amundsen/allTags/GET_ALL_TAGS_FAILURE',
} }
export interface GetAllTagsRequest { export interface GetAllTagsRequest {
......
...@@ -7,7 +7,7 @@ import { ...@@ -7,7 +7,7 @@ import {
import { import {
metadataAllTags, metadataAllTags,
} from '../api/metadata/v0'; } from './api/v0';
export function* getAllTagsWorker(): SagaIterator { export function* getAllTagsWorker(): SagaIterator {
try { try {
......
import axios from 'axios';
export function metadataPopularTables() {
return axios.get('/api/metadata/v0/popular_tables').then((response) => {
return response.data.results;
})
.catch((error) => {
return error.response.data.results;
});
}
...@@ -8,7 +8,7 @@ import { ...@@ -8,7 +8,7 @@ import {
import { import {
metadataPopularTables, metadataPopularTables,
} from '../api/metadata/v0'; } from './api/v0';
export function* getPopularTablesWorker(): SagaIterator { export function* getPopularTablesWorker(): SagaIterator {
......
...@@ -5,7 +5,7 @@ import feedback, { FeedbackReducerState } from './feedback/reducer'; ...@@ -5,7 +5,7 @@ import feedback, { FeedbackReducerState } from './feedback/reducer';
import popularTables, { PopularTablesReducerState } from './popularTables/reducer'; import popularTables, { PopularTablesReducerState } from './popularTables/reducer';
import search, { SearchReducerState } from './search/reducer'; import search, { SearchReducerState } from './search/reducer';
import tableMetadata, { TableMetadataReducerState } from './tableMetadata/reducer'; import tableMetadata, { TableMetadataReducerState } from './tableMetadata/reducer';
import tags, { TagReducerState } from './tags/reducer'; import allTags, { TagReducerState } from './allTags/reducer';
import user, { UserReducerState } from './user/reducer'; import user, { UserReducerState } from './user/reducer';
export interface GlobalState { export interface GlobalState {
...@@ -14,7 +14,7 @@ export interface GlobalState { ...@@ -14,7 +14,7 @@ export interface GlobalState {
popularTables: PopularTablesReducerState; popularTables: PopularTablesReducerState;
search: SearchReducerState; search: SearchReducerState;
tableMetadata: TableMetadataReducerState; tableMetadata: TableMetadataReducerState;
tags: TagReducerState; allTags: TagReducerState;
user: UserReducerState; user: UserReducerState;
} }
...@@ -24,6 +24,6 @@ export default combineReducers<GlobalState>({ ...@@ -24,6 +24,6 @@ export default combineReducers<GlobalState>({
popularTables, popularTables,
search, search,
tableMetadata, tableMetadata,
tags, allTags,
user, user,
}); });
...@@ -11,6 +11,8 @@ import { getPopularTablesWatcher } from './popularTables/sagas'; ...@@ -11,6 +11,8 @@ import { getPopularTablesWatcher } from './popularTables/sagas';
import { executeSearchWatcher } from './search/sagas'; import { executeSearchWatcher } from './search/sagas';
// TableDetail // TableDetail
import { updateTableOwnerWatcher } from './tableMetadata/owners/sagas';
import { updateTableTagsWatcher } from './tableMetadata/tags/sagas';
import { import {
getTableDataWatcher, getTableDataWatcher,
getColumnDescriptionWatcher, getColumnDescriptionWatcher,
...@@ -19,12 +21,10 @@ import { ...@@ -19,12 +21,10 @@ import {
getTableDescriptionWatcher, getTableDescriptionWatcher,
updateColumnDescriptionWatcher, updateColumnDescriptionWatcher,
updateTableDescriptionWatcher, updateTableDescriptionWatcher,
updateTableOwnerWatcher,
updateTagsWatcher,
} from './tableMetadata/sagas'; } from './tableMetadata/sagas';
// Tags // Tags
import { getAllTagsWatcher } from './tags/sagas'; import { getAllTagsWatcher } from './allTags/sagas';
// User // User
import { getCurrentUserWatcher } from "./user/sagas"; import { getCurrentUserWatcher } from "./user/sagas";
...@@ -40,7 +40,6 @@ export default function* rootSaga() { ...@@ -40,7 +40,6 @@ export default function* rootSaga() {
getPopularTablesWatcher(), getPopularTablesWatcher(),
// Tags // Tags
getAllTagsWatcher(), getAllTagsWatcher(),
updateTagsWatcher(),
// TableDetail // TableDetail
getTableDataWatcher(), getTableDataWatcher(),
getColumnDescriptionWatcher(), getColumnDescriptionWatcher(),
...@@ -50,6 +49,7 @@ export default function* rootSaga() { ...@@ -50,6 +49,7 @@ export default function* rootSaga() {
updateColumnDescriptionWatcher(), updateColumnDescriptionWatcher(),
updateTableDescriptionWatcher(), updateTableDescriptionWatcher(),
updateTableOwnerWatcher(), updateTableOwnerWatcher(),
updateTableTagsWatcher(),
// User // User
getCurrentUserWatcher(), getCurrentUserWatcher(),
]); ]);
......
/** TODO: We will introduce better typing for function parameters return types */
import { filterFromObj, sortTagsAlphabetical } from '../../utilMethods';
/**
* Generates the query string parameters needed for requests that act on a particular table resource.
*/
export function getTableParams(tableDataObject) {
const { cluster, database, schema, table_name } = tableDataObject;
return `db=${database}&cluster=${cluster}&schema=${schema}&table=${table_name}`;
}
/**
* Parses the response for table metadata to create a TableMetadata object
*/
export function getTableDataFromResponseData(responseData) {
return filterFromObj(responseData, ['owners', 'tags']);
}
/**
* Parses the response for table metadata to return the array of table owners
*/
export function getTableOwnersFromResponseData(responseData) {
return responseData.owners;
}
/**
* Parses the response for table metadata to return an array of sorted table tags
*/
export function getTableTagsFromResponseData(responseData) {
return responseData.tags.sort(sortTagsAlphabetical);
}
/** TODO: We will introduce better typing for requests and responses */
import axios from 'axios'; import axios from 'axios';
import { GetPreviewDataRequest } from '../../tableMetadata/reducer'; import { GetPreviewDataRequest } from '../../tableMetadata/reducer';
const API_PATH = '/api/metadata/v0'; const API_PATH = '/api/metadata/v0';
const sortTagsAlphabetical = (a, b) => a.tag_name.localeCompare(b.tag_name);
function getTableParams(tableDataObject) { /** HELPERS **/
const { cluster, database, schema, table_name } = tableDataObject; import {
return `db=${database}&cluster=${cluster}&schema=${schema}&table=${table_name}`; getTableParams,
} getTableDataFromResponseData,
getTableOwnersFromResponseData,
export function metadataPopularTables() { getTableTagsFromResponseData
return axios.get(`${API_PATH}/popular_tables`).then((response) => { } from './helpers';
return response.data.results;
})
.catch((error) => {
return error.response.data.results;
});
}
export function metadataAllTags() {
return axios.get(`${API_PATH}/tags`).then((response) => {
return response.data.tags.sort(sortTagsAlphabetical);
})
.catch((error) => {
return error.response.data.tags.sort(sortTagsAlphabetical);
});
}
export function metadataTableTags(tableData) { export function metadataTableTags(tableData) {
const tableParams = getTableParams(tableData); const tableParams = getTableParams(tableData);
return axios.get(`${API_PATH}/table?${tableParams}&index=&source=`).then((response) => { return axios.get(`${API_PATH}/table?${tableParams}&index=&source=`).then((response) => {
const newTableData = response.data.tableData; return getTableTagsFromResponseData(response.data.tableData);
newTableData.tags = newTableData.tags.sort(sortTagsAlphabetical);
return newTableData;
}) })
.catch((error) => { .catch((error) => {
return tableData; return [];
}); });
} }
...@@ -62,12 +45,16 @@ export function metadataGetTableData(action) { ...@@ -62,12 +45,16 @@ export function metadataGetTableData(action) {
const tableParams = getTableParams(action); const tableParams = getTableParams(action);
return axios.get(`${API_PATH}/table?${tableParams}&index=${searchIndex}&source=${source}`).then((response) => { return axios.get(`${API_PATH}/table?${tableParams}&index=${searchIndex}&source=${source}`).then((response) => {
const tableData = response.data.tableData; const responseData = response.data.tableData;
tableData.tags = tableData.tags.sort(sortTagsAlphabetical); return {
return { tableData, statusCode: response.status }; data: getTableDataFromResponseData(responseData),
owners: getTableOwnersFromResponseData(responseData),
tags: getTableTagsFromResponseData(responseData),
statusCode: response.status,
};
}) })
.catch((error) => { .catch((error) => {
return { tableData: {}, statusCode: error.response.status }; return { data: {}, owners: [], tags: [], statusCode: error.response.status };
}); });
} }
......
import { GetTableData, GetTableDataRequest, GetTableDataResponse } from '../reducer';
import { User } from '../../../components/TableDetail/types';
/* updateTableOwner */
export enum UpdateTableOwner {
ACTION = 'amundsen/tableMetadata/UPDATE_TABLE_OWNER',
SUCCESS = 'amundsen/tableMetadata/UPDATE_TABLE_OWNER_SUCCESS',
FAILURE = 'amundsen/tableMetadata/UPDATE_TABLE_OWNER_FAILURE',
}
export enum UpdateMethod {
PUT = 'PUT',
DELETE = 'DELETE',
}
export interface UpdateTableOwnerRequest {
type: UpdateTableOwner.ACTION;
method: UpdateMethod;
value: string;
onSuccess?: () => any;
onFailure?: () => any;
}
interface UpdateTableOwnerResponse {
type: UpdateTableOwner.SUCCESS | UpdateTableOwner.FAILURE;
}
export function updateTableOwner(value: string, method: UpdateMethod, onSuccess?: () => any, onFailure?: () => any): UpdateTableOwnerRequest {
return {
value,
method,
onSuccess,
onFailure,
type: UpdateTableOwner.ACTION,
};
}
/* end updateTableOwner */
export type TableOwnerReducerAction =
GetTableDataRequest | GetTableDataResponse |
UpdateTableOwnerRequest | UpdateTableOwnerResponse;
export interface TableOwnerReducerState {
isLoading: boolean;
owners: User[];
}
export const initialOwnersState: TableOwnerReducerState = {
isLoading: true,
owners: [],
};
export default function reducer(state: TableOwnerReducerState = initialOwnersState, action: TableOwnerReducerAction): TableOwnerReducerState {
switch (action.type) {
case GetTableData.ACTION:
return { isLoading: true, owners: [] };
case GetTableData.FAILURE:
case GetTableData.SUCCESS:
return { isLoading: false, owners: action.payload.owners };
default:
return state;
}
}
import { call, select, takeEvery } from 'redux-saga/effects';
import { SagaIterator } from 'redux-saga';
import { UpdateTableOwner, UpdateTableOwnerRequest } from './reducer';
import { metadataUpdateTableOwner } from '../api/v0';
// updateTableOwner
export function* updateTableOwnerWorker(action: UpdateTableOwnerRequest): SagaIterator {
const state = yield select();
try {
yield call(metadataUpdateTableOwner, action.value, action.method, state.tableMetadata.tableData);
if (action.onSuccess) {
yield call(action.onSuccess);
}
} catch (e) {
if (action.onFailure) {
yield call(action.onFailure);
}
}
}
export function* updateTableOwnerWatcher(): SagaIterator {
yield takeEvery(UpdateTableOwner.ACTION, updateTableOwnerWorker);
}
import { PreviewData, PreviewQueryParams, TableMetadata } from '../../components/TableDetail/types'; import { PreviewData, PreviewQueryParams, TableMetadata, User } from '../../components/TableDetail/types';
import { UpdateTagData } from '../../components/Tags/types'; import { Tag } from '../../components/Tags/types';
import tableOwnersReducer, { initialOwnersState, TableOwnerReducerState } from './owners/reducer';
import tableTagsReducer, {
initialTagsState,
TableTagsReducerState,
UpdateTags,
UpdateTagsRequest,
UpdateTagsResponse,
} from './tags/reducer';
/* getTableData */ /* getTableData */
export enum GetTableData { export enum GetTableData {
...@@ -18,11 +27,13 @@ export interface GetTableDataRequest { ...@@ -18,11 +27,13 @@ export interface GetTableDataRequest {
table_name: string; table_name: string;
} }
interface GetTableDataResponse { export interface GetTableDataResponse {
type: GetTableData.SUCCESS | GetTableData.FAILURE; type: GetTableData.SUCCESS | GetTableData.FAILURE;
payload: { payload: {
statusCode: number; statusCode: number;
tableData: TableMetadata; data: TableMetadata;
owners: User[];
tags: Tag[];
} }
} }
...@@ -94,41 +105,6 @@ export function updateTableDescription(newValue: string, onSuccess?: () => any, ...@@ -94,41 +105,6 @@ export function updateTableDescription(newValue: string, onSuccess?: () => any,
} }
/* end updateTableDescription */ /* end updateTableDescription */
/* updateTableOwner */
export enum UpdateTableOwner {
ACTION = 'amundsen/tableMetadata/UPDATE_TABLE_OWNER',
SUCCESS = 'amundsen/tableMetadata/UPDATE_TABLE_OWNER_SUCCESS',
FAILURE = 'amundsen/tableMetadata/UPDATE_TABLE_OWNER_FAILURE',
}
export enum UpdateMethod {
PUT = 'PUT',
DELETE = 'DELETE',
}
export interface UpdateTableOwnerRequest {
type: UpdateTableOwner.ACTION;
method: UpdateMethod;
value: string;
onSuccess?: () => any;
onFailure?: () => any;
}
interface UpdateTableOwnerResponse {
type: UpdateTableOwner.SUCCESS | UpdateTableOwner.FAILURE;
}
export function updateTableOwner(value: string, method: UpdateMethod, onSuccess?: () => any, onFailure?: () => any): UpdateTableOwnerRequest {
return {
value,
method,
onSuccess,
onFailure,
type: UpdateTableOwner.ACTION,
};
}
/* end updateTableOwner */
/* getColumnDescription */ /* getColumnDescription */
export enum GetColumnDescription { export enum GetColumnDescription {
ACTION = 'amundsen/tableMetadata/GET_COLUMN_DESCRIPTION', ACTION = 'amundsen/tableMetadata/GET_COLUMN_DESCRIPTION',
...@@ -187,30 +163,6 @@ export function updateColumnDescription(newValue: string, columnIndex: number, o ...@@ -187,30 +163,6 @@ export function updateColumnDescription(newValue: string, columnIndex: number, o
} }
/* end updateColumnDescription */ /* end updateColumnDescription */
/* updateTags */
export enum UpdateTags {
ACTION = 'amundsen/tags/UPDATE_TAGS',
SUCCESS = 'amundsen/tags/UPDATE_TAGS_SUCCESS',
FAILURE = 'amundsen/tags/UPDATE_TAGS_FAILURE',
}
export interface UpdateTagsRequest {
type: UpdateTags.ACTION,
tagArray: UpdateTagData[];
}
interface UpdateTagsResponse {
type: UpdateTags.SUCCESS | UpdateTags.FAILURE,
payload: TableMetadata;
}
export function updateTags(tagArray: UpdateTagData[]): UpdateTagsRequest {
return {
tagArray,
type: UpdateTags.ACTION,
};
}
/* end updateTags */
/* getLastIndexed */ /* getLastIndexed */
export enum GetLastIndexed { export enum GetLastIndexed {
ACTION = 'amundsen/tableMetadata/GET_LAST_UPDATED', ACTION = 'amundsen/tableMetadata/GET_LAST_UPDATED',
...@@ -260,42 +212,68 @@ export type TableMetadataReducerAction = ...@@ -260,42 +212,68 @@ export type TableMetadataReducerAction =
GetTableDataRequest | GetTableDataResponse | GetTableDataRequest | GetTableDataResponse |
GetTableDescriptionRequest | GetTableDescriptionResponse | GetTableDescriptionRequest | GetTableDescriptionResponse |
UpdateTableDescriptionRequest | UpdateTableDescriptionResponse | UpdateTableDescriptionRequest | UpdateTableDescriptionResponse |
UpdateTableOwnerRequest | UpdateTableOwnerResponse |
GetColumnDescriptionRequest | GetColumnDescriptionResponse | GetColumnDescriptionRequest | GetColumnDescriptionResponse |
UpdateColumnDescriptionRequest | UpdateColumnDescriptionResponse | UpdateColumnDescriptionRequest | UpdateColumnDescriptionResponse |
UpdateTagsRequest | UpdateTagsResponse |
GetLastIndexedRequest | GetLastIndexedResponse | GetLastIndexedRequest | GetLastIndexedResponse |
GetPreviewDataRequest | GetPreviewDataResponse; GetPreviewDataRequest | GetPreviewDataResponse |
UpdateTagsRequest | UpdateTagsResponse ;
export interface TableMetadataReducerState { export interface TableMetadataReducerState {
isLoading: boolean; isLoading: boolean;
isLoadingTags: boolean;
lastIndexed: number; lastIndexed: number;
preview: PreviewDataState; preview: PreviewDataState;
statusCode: number; statusCode: number;
tableData: TableMetadata; tableData: TableMetadata;
tableOwners: TableOwnerReducerState;
tableTags: TableTagsReducerState;
} }
const initialPreviewState = { const initialPreviewState = {
data: {}, data: {},
status: null, status: null,
}; };
const initialTableDataState: TableMetadata = {
columns: [],
is_editable: false,
schema: '',
table_name: '',
table_description: '',
table_writer: { application_url: '', description: '', id: '', name: '' },
partition: { is_partitioned: false },
table_readers: [],
source: { source: '', source_type: '' },
watermarks: [],
};
const initialState: TableMetadataReducerState = { const initialState: TableMetadataReducerState = {
isLoading: true, isLoading: true,
isLoadingTags: true,
lastIndexed: null, lastIndexed: null,
preview: initialPreviewState, preview: initialPreviewState,
statusCode: null, statusCode: null,
tableData: {} as TableMetadata, tableData: initialTableDataState,
tableOwners: initialOwnersState,
tableTags: initialTagsState,
}; };
export default function reducer(state: TableMetadataReducerState = initialState, action: TableMetadataReducerAction): TableMetadataReducerState { export default function reducer(state: TableMetadataReducerState = initialState, action: TableMetadataReducerAction): TableMetadataReducerState {
switch (action.type) { switch (action.type) {
case GetTableData.ACTION: case GetTableData.ACTION:
return { ...state, isLoading: true, isLoadingTags: true, preview: initialPreviewState }; return {
...state,
isLoading: true,
preview: initialPreviewState,
tableOwners: tableOwnersReducer(state.tableOwners, action),
tableTags: tableTagsReducer(state.tableTags, action),
};
case GetTableData.FAILURE: case GetTableData.FAILURE:
case GetTableData.SUCCESS: case GetTableData.SUCCESS:
return { ...state, isLoading: false, isLoadingTags: false, statusCode: action.payload.statusCode, tableData: action.payload.tableData }; return {
...state,
isLoading: false,
statusCode: action.payload.statusCode,
tableData: action.payload.data,
tableOwners: tableOwnersReducer(state.tableOwners, action),
tableTags: tableTagsReducer(state.tableTags, action),
};
case GetTableDescription.FAILURE: case GetTableDescription.FAILURE:
case GetTableDescription.SUCCESS: case GetTableDescription.SUCCESS:
return { ...state, tableData: action.payload }; return { ...state, tableData: action.payload };
...@@ -309,12 +287,10 @@ export default function reducer(state: TableMetadataReducerState = initialState, ...@@ -309,12 +287,10 @@ export default function reducer(state: TableMetadataReducerState = initialState,
case GetPreviewData.SUCCESS: case GetPreviewData.SUCCESS:
case GetPreviewData.FAILURE: case GetPreviewData.FAILURE:
return { ...state, preview: action.payload }; return { ...state, preview: action.payload };
case UpdateTags.ACTION:
case UpdateTags.FAILURE: case UpdateTags.FAILURE:
return { ...state, isLoadingTags: false };
case UpdateTags.SUCCESS: case UpdateTags.SUCCESS:
return { ...state, isLoadingTags: false, tableData: action.payload }; return { ...state, tableTags: tableTagsReducer(state.tableTags, action) };
case UpdateTags.ACTION:
return { ...state, isLoadingTags: true };
default: default:
return state; return state;
} }
......
...@@ -9,8 +9,6 @@ import { ...@@ -9,8 +9,6 @@ import {
GetTableDescription, GetTableDescriptionRequest, GetTableDescription, GetTableDescriptionRequest,
UpdateColumnDescription, UpdateColumnDescriptionRequest, UpdateColumnDescription, UpdateColumnDescriptionRequest,
UpdateTableDescription, UpdateTableDescriptionRequest, UpdateTableDescription, UpdateTableDescriptionRequest,
UpdateTableOwner, UpdateTableOwnerRequest,
UpdateTags, UpdateTagsRequest,
} from './reducer'; } from './reducer';
import { import {
...@@ -21,19 +19,16 @@ import { ...@@ -21,19 +19,16 @@ import {
metadataGetTableDescription, metadataGetTableDescription,
metadataUpdateColumnDescription, metadataUpdateColumnDescription,
metadataUpdateTableDescription, metadataUpdateTableDescription,
metadataUpdateTableOwner, } from './api/v0';
metadataUpdateTableTags,
metadataTableTags,
} from '../api/metadata/v0';
// getTableData // getTableData
export function* getTableDataWorker(action: GetTableDataRequest): SagaIterator { export function* getTableDataWorker(action: GetTableDataRequest): SagaIterator {
let tableData; let tableData;
try { try {
tableData = yield call(metadataGetTableData, action); const { data, owners, tags } = yield call(metadataGetTableData, action);
yield put({ type: GetTableData.SUCCESS, payload: tableData }); yield put({ type: GetTableData.SUCCESS, payload: { data, owners, tags } });
} catch (e) { } catch (e) {
yield put({ type: GetTableData.FAILURE, payload: tableData }); yield put({ type: GetTableData.FAILURE, payload: { data: {}, owners: [], tags: [] } });
} }
} }
...@@ -82,25 +77,6 @@ export function* updateTableDescriptionWatcher(): SagaIterator { ...@@ -82,25 +77,6 @@ export function* updateTableDescriptionWatcher(): SagaIterator {
yield takeEvery(UpdateTableDescription.ACTION, updateTableDescriptionWorker); yield takeEvery(UpdateTableDescription.ACTION, updateTableDescriptionWorker);
} }
// updateTableOwner
export function* updateTableOwnerWorker(action: UpdateTableOwnerRequest): SagaIterator {
const state = yield select();
try {
yield call(metadataUpdateTableOwner, action.value, action.method, state.tableMetadata.tableData);
if (action.onSuccess) {
yield call(action.onSuccess);
}
} catch (e) {
if (action.onFailure) {
yield call(action.onFailure);
}
}
}
export function* updateTableOwnerWatcher(): SagaIterator {
yield takeEvery(UpdateTableOwner.ACTION, updateTableOwnerWorker);
}
// getColumnDescription // getColumnDescription
export function* getColumnDescriptionWorker(action: GetColumnDescriptionRequest): SagaIterator { export function* getColumnDescriptionWorker(action: GetColumnDescriptionRequest): SagaIterator {
const state = yield select(); const state = yield select();
...@@ -142,24 +118,6 @@ export function* updateColumnDescriptionWatcher(): SagaIterator { ...@@ -142,24 +118,6 @@ export function* updateColumnDescriptionWatcher(): SagaIterator {
yield takeEvery(UpdateColumnDescription.ACTION, updateColumnDescriptionWorker); yield takeEvery(UpdateColumnDescription.ACTION, updateColumnDescriptionWorker);
} }
// updateTags
export function* updateTagsWorker(action: UpdateTagsRequest): SagaIterator {
const state = yield select();
const tableData = state.tableMetadata.tableData;
try {
yield all(metadataUpdateTableTags(action, tableData));
const newTableData = yield call(metadataTableTags, tableData);
console.log(newTableData);
yield put({ type: UpdateTags.SUCCESS, payload: newTableData });
} catch (e) {
yield put({ type: UpdateTags.FAILURE, payload: tableData });
}
}
export function* updateTagsWatcher(): SagaIterator {
yield takeEvery(UpdateTags.ACTION, updateTagsWorker);
}
// getLastIndexed // getLastIndexed
export function* getLastIndexedWorker(action: GetLastIndexedRequest): SagaIterator { export function* getLastIndexedWorker(action: GetLastIndexedRequest): SagaIterator {
try { try {
......
import { GetTableData, GetTableDataRequest, GetTableDataResponse } from '../reducer';
import { UpdateTagData, Tag } from '../../../components/Tags/types';
/* updateTags */
export enum UpdateTags {
ACTION = 'amundsen/tags/UPDATE_TAGS',
SUCCESS = 'amundsen/tags/UPDATE_TAGS_SUCCESS',
FAILURE = 'amundsen/tags/UPDATE_TAGS_FAILURE',
}
export interface UpdateTagsRequest {
type: UpdateTags.ACTION,
tagArray: UpdateTagData[];
}
export interface UpdateTagsResponse {
type: UpdateTags.SUCCESS | UpdateTags.FAILURE,
payload: Tag[];
}
export function updateTags(tagArray: UpdateTagData[]): UpdateTagsRequest {
return {
tagArray,
type: UpdateTags.ACTION,
};
}
/* end updateTags */
export type TableTagsReducerAction =
GetTableDataRequest | GetTableDataResponse |
UpdateTagsRequest | UpdateTagsResponse;
export interface TableTagsReducerState {
isLoading: boolean;
tags: Tag[];
}
export const initialTagsState: TableTagsReducerState = {
isLoading: true,
tags: [],
};
export default function reducer(state: TableTagsReducerState = initialTagsState, action: TableTagsReducerAction): TableTagsReducerState {
switch (action.type) {
case GetTableData.ACTION:
return { isLoading: true, tags: [] };
case GetTableData.FAILURE:
case GetTableData.SUCCESS:
return { isLoading: false, tags: action.payload.tags };
case UpdateTags.FAILURE:
return { ...state, isLoading: false };
case UpdateTags.SUCCESS:
return { isLoading: false, tags: action.payload };
case UpdateTags.ACTION:
return { ...state, isLoading: true };
default:
return state;
}
}
import { all, call, put, select, takeEvery } from 'redux-saga/effects';
import { SagaIterator } from 'redux-saga';
import { UpdateTags, UpdateTagsRequest } from './reducer';
import { metadataUpdateTableTags, metadataTableTags } from '../api/v0';
// updateTags
export function* updateTableTagsWorker(action: UpdateTagsRequest): SagaIterator {
const state = yield select();
const tableData = state.tableMetadata.tableData;
try {
yield all(metadataUpdateTableTags(action, tableData));
const newTags = yield call(metadataTableTags, tableData);
yield put({ type: UpdateTags.SUCCESS, payload: newTags });
} catch (e) {
yield put({ type: UpdateTags.FAILURE, payload: [] });
}
}
export function* updateTableTagsWatcher(): SagaIterator {
yield takeEvery(UpdateTags.ACTION, updateTableTagsWorker);
}
import { Tag } from '../components/Tags/types';
export function sortTagsAlphabetical(a: Tag, b: Tag): number {
return a.tag_name.localeCompare(b.tag_name);
}
export function extractFromObj(initialObj: object, desiredKeys: string[]): object {
return Object.keys(initialObj)
.filter((key) => {
return desiredKeys.indexOf(key) > -1;
})
.reduce((obj, key) => {
obj[key] = initialObj[key];
return obj;
}, {});
}
export function filterFromObj(initialObj: object, rejectedKeys: string[]): object {
return Object.keys(initialObj)
.filter((key) => {
return rejectedKeys.indexOf(key) === -1;
})
.reduce((obj, key) => {
obj[key] = initialObj[key];
return obj;
}, {});
}
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