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

feat: Add feature discovery route and page #1185

Merged
merged 5 commits into from
Jun 9, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 7 additions & 20 deletions frontend/amundsen_application/static/.betterer.results
Original file line number Diff line number Diff line change
Expand Up @@ -505,17 +505,14 @@ exports[`eslint`] = {
"js/components/Tags/index.tsx:3468508233": [
[38, 4, 21, "Must use destructuring props assignment", "4236634811"]
],
"js/config/config-default.ts:1497564975": [
"js/config/config-default.ts:54755128": [
[2, 0, 72, "\`../interfaces\` import should occur before import of \`./config-types\`", "1449508543"],
[236, 6, 21, "\'partitionKey\' is defined but never used.", "399589312"],
[237, 6, 23, "\'partitionValue\' is defined but never used.", "793372348"]
[281, 6, 21, "\'partitionKey\' is defined but never used.", "399589312"],
[282, 6, 23, "\'partitionValue\' is defined but never used.", "793372348"]
],
"js/config/config-utils.ts:2658622130": [
[11, 0, 45, "\`../interfaces\` import should occur before import of \`./config-types\`", "3885176344"]
],
"js/ducks/announcements/api/v0.ts:908063915": [
[30, 13, 64, "Expected the Promise rejection reason to be an Error.", "3665078104"]
],
"js/ducks/announcements/index.spec.ts:1898496537": [
[3, 0, 148, "\`.\` import should occur after import of \`./types\`", "4154971894"]
],
Expand All @@ -542,8 +539,7 @@ exports[`eslint`] = {
[0, 16, 13, "\'AxiosResponse\' is defined but never used.", "1743879434"]
],
"js/ducks/dashboard/api/v0.ts:2755958463": [
[38, 28, 104, "Do not nest ternary expressions.", "1163212497"],
[45, 13, 68, "Expected the Promise rejection reason to be an Error.", "2764124112"]
[38, 28, 104, "Do not nest ternary expressions.", "1163212497"]
],
"js/ducks/issue/reducer.ts:1774302197": [
[119, 6, 56, "Unexpected lexical declaration in case block.", "2031834906"]
Expand All @@ -557,16 +553,9 @@ exports[`eslint`] = {
[250, 8, 31, "Use object destructuring.", "507617405"],
[251, 8, 45, "Use object destructuring.", "244310461"]
],
"js/ducks/lastIndexed/api/v0.ts:100101993": [
[18, 13, 44, "Expected the Promise rejection reason to be an Error.", "107682302"]
],
"js/ducks/lastIndexed/sagas.ts:1498244597": [
[7, 2, 29, "\'action\' is defined but never used.", "566797395"]
],
"js/ducks/lineage/api/v0.ts:63450243": [
[19, 13, 26, "Expected the Promise rejection reason to be an Error.", "875716520"],
[44, 13, 26, "Expected the Promise rejection reason to be an Error.", "875716520"]
],
"js/ducks/middlewares/analyticsMiddleware.ts:3943673455": [
[11, 7, 8, "\'getState\' is defined but never used.", "1919118020"]
],
Expand Down Expand Up @@ -594,9 +583,7 @@ exports[`eslint`] = {
],
"js/ducks/tableMetadata/api/v0.ts:1722284731": [
[75, 8, 23, "Use object destructuring.", "1142306891"],
[78, 13, 39, "Expected the Promise rejection reason to be an Error.", "3871091426"],
[125, 23, -4008, "Expected to return a value at the end of arrow function.", "5381"],
[181, 13, 32, "Expected the Promise rejection reason to be an Error.", "2773728948"]
[125, 23, -4008, "Expected to return a value at the end of arrow function.", "5381"]
],
"js/ducks/tableMetadata/index.spec.ts:2466548220": [
[480, 22, 11, "\'mockSuccess\' is already declared in the upper scope.", "1120045516"],
Expand Down Expand Up @@ -1003,15 +990,15 @@ exports[`eslint`] = {
[208, 14, 151, "A control must be associated with a text label.", "1015004405"],
[218, 12, 432, "A control must be associated with a text label.", "534436217"]
],
"js/pages/TableDetailPage/SourceLink/index.spec.tsx:4268867941": [
"js/pages/TableDetailPage/SourceLink/index.spec.tsx:3686659452": [
[19, 55, 10, "Prop spreading is forbidden", "480399587"]
],
"js/pages/TableDetailPage/TableHeaderBullets/index.spec.tsx:3978961134": [
[45, 28, 10, "Prop spreading is forbidden", "480399587"],
[91, 6, 25, "Use object destructuring.", "354229464"],
[92, 6, 29, "Use object destructuring.", "2645724888"]
],
"js/pages/TableDetailPage/TableHeaderBullets/index.tsx:3687188386": [
"js/pages/TableDetailPage/TableHeaderBullets/index.tsx:1080737806": [
[35, 25, 19, "Must use destructuring props assignment", "2861102024"],
[40, 4, 25, "Must use destructuring props assignment", "2288791878"],
[45, 6, 17, "Must use destructuring props assignment", "2741866010"],
Expand Down
1 change: 0 additions & 1 deletion frontend/amundsen_application/static/.betterer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ export default {
'no-useless-return': 'error',
'no-void': 'error',
'prefer-destructuring': 'error',
'prefer-promise-reject-errors': 'error',
'react/button-has-type': 'error',
'react/destructuring-assignment': 'error',
'react/jsx-boolean-value': 'error',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,47 @@ const configDefault: AppConfig = {
],
notices: {},
},
[ResourceType.feature]: {
displayName: 'ML Features',
supportedSources: {
bigquery: {
displayName: 'BigQuery',
iconClass: 'icon-bigquery',
},
delta: {
displayName: 'Delta',
iconClass: 'icon-delta',
},
dremio: {
displayName: 'Dremio',
iconClass: 'icon-dremio',
},
druid: {
displayName: 'Druid',
iconClass: 'icon-druid',
},
hive: {
displayName: 'Hive',
iconClass: 'icon-hive',
},
presto: {
displayName: 'Presto',
iconClass: 'icon-presto',
},
postgres: {
displayName: 'Postgres',
iconClass: 'icon-postgres',
},
redshift: {
displayName: 'Redshift',
iconClass: 'icon-redshift',
},
snowflake: {
displayName: 'Snowflake',
iconClass: 'icon-snowflake',
},
},
},
[ResourceType.table]: {
displayName: 'Datasets',
supportedSources: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ interface ResourceConfig {
[ResourceType.dashboard]: BaseResourceConfig;
[ResourceType.table]: TableResourceConfig;
[ResourceType.user]: BaseResourceConfig;
[ResourceType.feature]: BaseResourceConfig;
}

/**
Expand Down
Empty file.
33 changes: 33 additions & 0 deletions frontend/amundsen_application/static/js/ducks/feature/api/v0.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import axios, { AxiosResponse } from 'axios';
import * as qs from 'simple-query-string';

import { FeatureMetadata } from 'interfaces/Feature';

export type GetFeatureAPI = {
msg: string;
featureData: FeatureMetadata;
};

const FEATURE_BASE = '/api/metadata/v0';

export function getFeature(key: string, index?: string, source?: string) {
const queryParams = qs.stringify({ key, index, source });
return axios
.get(`${FEATURE_BASE}/feature?${queryParams}`)
.then((response: AxiosResponse<GetFeatureAPI>) => {
const { data, status } = response;
return {
feature: data.featureData,
statusCode: status,
};
})
.catch((e) => {
const { response } = e;
const statusMessage = response.data?.msg;
const statusCode = response?.status || 500;
return Promise.reject({
statusCode,
statusMessage,
});
});
}
Empty file.
105 changes: 105 additions & 0 deletions frontend/amundsen_application/static/js/ducks/feature/reducer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import {
GetFeature,
GetFeatureRequest,
GetFeatureResponse,
GetFeaturePayload,
} from 'ducks/feature/types';
import { FeatureMetadata } from 'interfaces/Feature';

/* Actions */

export function getFeature(
key: string,
index?: string,
source?: string
): GetFeatureRequest {
return {
payload: {
key,
index,
source,
},
type: GetFeature.REQUEST,
};
}

export function getFeatureSuccess(payload: GetFeaturePayload) {
return {
payload,
type: GetFeature.SUCCESS,
};
}

export function getFeatureFailure(
payload: GetFeaturePayload
): GetFeatureResponse {
return {
payload,
type: GetFeature.FAILURE,
};
}

/* Reducer */

export interface FeatureReducerState {
isLoading: boolean;
statusCode: number | null;
feature: FeatureMetadata;
}

export const initialFeatureState: FeatureMetadata = {
key: '',
name: '',
version: '',
status: '',
feature_group: '',
entity: [],
data_type: '',
availability: [],
description: '',
owners: [],
badges: [],
owner_tags: [],
tags: [],
programmatic_descriptions: [],
watermarks: [],
stats: [],
last_updated_timestamp: 0,
created_timestamp: 0,
};

export const initialState: FeatureReducerState = {
isLoading: true,
statusCode: null,
feature: initialFeatureState,
};

export default function reducer(
state: FeatureReducerState = initialState,
action
): FeatureReducerState {
switch (action.type) {
case GetFeature.REQUEST:
return {
...state,
statusCode: null,
isLoading: true,
};
case GetFeature.FAILURE:
return {
...state,
isLoading: false,
statusCode: action.payload.statusCode,
feature: initialFeatureState,
};
case GetFeature.SUCCESS:
return {
...state,
isLoading: false,
statusCode: action.payload.statusCode,
feature: action.payload.feature,
};
default:
return state;
}
}
Empty file.
21 changes: 21 additions & 0 deletions frontend/amundsen_application/static/js/ducks/feature/sagas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { SagaIterator } from 'redux-saga';
import { call, put, takeEvery } from 'redux-saga/effects';

import * as API from './api/v0';
import { getFeatureSuccess, getFeatureFailure } from './reducer';
import { GetFeature } from './types';

export function* getFeatureWorker(action): SagaIterator {
try {
const { key, searchIndex, source } = action.payload;
const response = yield call(API.getFeature, key, searchIndex, source);

yield put(getFeatureSuccess(response));
} catch (error) {
yield put(getFeatureFailure(error));
}
}

export function* getFeatureWatcher(): SagaIterator {
yield takeEvery(GetFeature.REQUEST, getFeatureWorker);
}
27 changes: 27 additions & 0 deletions frontend/amundsen_application/static/js/ducks/feature/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { FeatureMetadata } from 'interfaces/Feature';

export enum GetFeature {
REQUEST = 'amundsen/feature/GET_FEATURE_REQUEST',
SUCCESS = 'amundsen/feature/GET_FEATURE_SUCCESS',
FAILURE = 'amundsen/feature/GET_FEATURE_FAILURE',
}

export interface GetFeatureRequest {
type: GetFeature.REQUEST;
payload: {
key: string;
index?: string;
source?: string;
};
}

export interface GetFeatureResponse {
type: GetFeature.SUCCESS | GetFeature.FAILURE;
payload: GetFeaturePayload;
}

export interface GetFeaturePayload {
feature?: FeatureMetadata;
statusCode?: number;
statusMessage?: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { combineReducers } from 'redux';

import dashboard, { DashboardReducerState } from 'ducks/dashboard/reducer';
import feature, { FeatureReducerState } from 'ducks/feature/reducer';
import announcements, { AnnouncementsReducerState } from './announcements';
import feedback, { FeedbackReducerState } from './feedback/reducer';
import popularTables, {
Expand All @@ -26,6 +27,7 @@ export interface GlobalState {
announcements: AnnouncementsReducerState;
bookmarks: BookmarkReducerState;
dashboard: DashboardReducerState;
feature: FeatureReducerState;
feedback: FeedbackReducerState;
issue: IssueReducerState;
notification: NotificationReducerState;
Expand All @@ -43,6 +45,7 @@ const rootReducer = combineReducers<GlobalState>({
announcements,
bookmarks,
dashboard,
feature,
feedback,
issue,
notification,
Expand Down
5 changes: 5 additions & 0 deletions frontend/amundsen_application/static/js/ducks/rootSaga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@ import {

// Dashboard
import { getDashboardWatcher } from 'ducks/dashboard/sagas';
import { getFeatureWatcher } from 'ducks/feature/sagas';
import { getAnnouncementsWatcher } from './announcements/sagas';

// Notifications
import { submitNotificationWatcher } from './notification/sagas';

// Feature

// FeedbackForm
import { submitFeedbackWatcher } from './feedback/sagas';

Expand Down Expand Up @@ -84,6 +87,8 @@ export default function* rootSaga() {
getDashboardWatcher(),
// Notification
submitNotificationWatcher(),
// Feature
getFeatureWatcher(),
// FeedbackForm
submitFeedbackWatcher(),
// Issues
Expand Down
Loading