From 6e10626f496ef0d67fc97d3b95b549a8a2d69cb1 Mon Sep 17 00:00:00 2001 From: Lars Liden Date: Wed, 20 Sep 2017 16:49:25 -0700 Subject: [PATCH] UI retrieves info about the bot --- package-lock.json | 6 ++-- package.json | 2 +- src/actions/fetchActions.ts | 17 ++++++++- src/containers/BLISAppsHomepage.tsx | 6 ++-- src/containers/TrainDialogsList.tsx | 54 ++++++++++++++++++++++------- src/epics/apiHelpers.ts | 15 ++++++-- src/epics/fetchEpics.ts | 8 ++++- src/epics/root.ts | 3 +- src/reducers/botReducer.ts | 19 ++++++++++ src/reducers/displayReducer.ts | 3 ++ src/reducers/root.ts | 2 ++ src/types/ActionObject.ts | 9 +++-- src/types/ActionTypes.ts | 2 ++ src/types/StateTypes.ts | 5 ++- 14 files changed, 125 insertions(+), 26 deletions(-) create mode 100644 src/reducers/botReducer.ts diff --git a/package-lock.json b/package-lock.json index 0c076150..c9c623ae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -495,9 +495,9 @@ "integrity": "sha1-muuabF6IY4qtFx4Wf1kAq+JINdA=" }, "blis-models": { - "version": "0.42.1", - "resolved": "https://dialearn.pkgs.visualstudio.com/_packaging/BLIS-SDK/npm/registry/blis-models/-/blis-models-0.42.1.tgz", - "integrity": "sha1-RI4wWqGQFPKcvF2FJq+hbXD+XI8=", + "version": "0.44.2", + "resolved": "https://dialearn.pkgs.visualstudio.com/_packaging/BLIS-SDK/npm/registry/blis-models/-/blis-models-0.44.2.tgz", + "integrity": "sha1-uNo8xjqW/Y/XkiZ/7G/n69GBTzo=", "requires": { "json-typescript-mapper": "1.1.3", "tslib": "1.7.1" diff --git a/package.json b/package.json index 9c89ec05..84eb86a0 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "dependencies": { "awesome-typescript-loader": "^3.1.3", "axios": "^0.16.2", - "blis-models": "^0.42.1", + "blis-models": "^0.44.2", "blis-webchat": "^0.12.1", "jquery": "^3.2.1", "office-ui-fabric-react": "^4.23.0", diff --git a/src/actions/fetchActions.ts b/src/actions/fetchActions.ts index da7eab4c..9cb1330e 100644 --- a/src/actions/fetchActions.ts +++ b/src/actions/fetchActions.ts @@ -1,6 +1,6 @@ import { ActionObject } from '../types' import { AT } from '../types/ActionTypes' -import { BlisAppBase, BlisAppMetaData, BlisAppList, +import { BlisAppBase, BlisAppMetaData, BlisAppList, BotInfo, EntityBase, EntityMetaData, EntityList, ActionBase, ActionMetaData, ActionList, ActionTypes, TrainDialog, LogDialog, @@ -36,6 +36,21 @@ export const fetchAllLogDialogsFulfilled = (logDialogs: LogDialog[]): ActionObje } } +export const fetchBotInfoAsync = (): ActionObject => { + //needs a fulfilled version to handle response from Epic + return { + type: AT.FETCH_BOTINFO_ASYNC + } +} + +export const fetchBotInfoFulfilled = (botInfo: BotInfo): ActionObject => { + //needs a fulfilled version to handle response from Epic + return { + type: AT.FETCH_BOTINFO_FULFILLED, + botInfo: botInfo + } +} + export const fetchApplicationsAsync = (key: string, userId : string): ActionObject => { //needs a fulfilled version to handle response from Epic return { diff --git a/src/containers/BLISAppsHomepage.tsx b/src/containers/BLISAppsHomepage.tsx index 0b9ab025..796d86ac 100644 --- a/src/containers/BLISAppsHomepage.tsx +++ b/src/containers/BLISAppsHomepage.tsx @@ -4,7 +4,7 @@ import AppAdmin from './AppAdmin'; import TeachSessionWindow from './TeachSessionWindow'; import TrainDialogWindow from './TrainDialogWindow' import ChatSessionWindow from './ChatSessionWindow'; -import { fetchApplicationsAsync } from '../actions/fetchActions' +import { fetchApplicationsAsync, fetchBotInfoAsync } from '../actions/fetchActions' import BLISAppsList from './BLISAppsList'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; @@ -25,6 +25,7 @@ class BLISAppsHomepage extends React.Component { displayedUserId: this.props.userId }) this.props.fetchApplications(this.props.userKey, this.props.userId); + this.props.fetchBotInfo(); } } render() { @@ -56,7 +57,8 @@ class BLISAppsHomepage extends React.Component { const mapDispatchToProps = (dispatch: any) => { return bindActionCreators({ - fetchApplications: fetchApplicationsAsync + fetchApplications: fetchApplicationsAsync, + fetchBotInfo: fetchBotInfoAsync }, dispatch); } diff --git a/src/containers/TrainDialogsList.tsx b/src/containers/TrainDialogsList.tsx index 4638c520..d4f521d9 100644 --- a/src/containers/TrainDialogsList.tsx +++ b/src/containers/TrainDialogsList.tsx @@ -14,27 +14,35 @@ import { DisplayMode } from '../types/const'; let columns: IColumn[] = [ { - key: 'firstUtterance', - name: 'First Utterance', - fieldName: 'firstUtterance', + key: 'firstInput', + name: 'First Input', + fieldName: 'firstInput', minWidth: 100, - maxWidth: 200, + maxWidth: 500, isResizable: true }, { - key: 'lastUtterance', - name: 'Last Utterance', - fieldName: 'lastUtterance', + key: 'lastInput', + name: 'Last Input', + fieldName: 'lastInput', minWidth: 100, - maxWidth: 200, + maxWidth: 500, + isResizable: true + }, + { + key: 'lastResponse', + name: 'Last Response', + fieldName: 'lastResponse', + minWidth: 100, + maxWidth: 500, isResizable: true }, { key: 'turns', name: 'Turns', fieldName: 'dialog', - minWidth: 100, - maxWidth: 200, + minWidth: 50, + maxWidth: 50, isResizable: true } ]; @@ -65,14 +73,35 @@ class TrainDialogsList extends React.Component { return "??"; } } + lastResponse(item: any) + { + try { + let scorerSteps = item.rounds[item.rounds.length-1].scorerSteps; + if (scorerSteps.length > 0) + { + let actionId = scorerSteps[scorerSteps.length-1].labelAction; + let action = this.props.actions.find(a => a.actionId = actionId); + if (action) + { + return action.payload; + } + } + return ""; + } + catch (err) { + return "??"; + } + } renderItemColumn(item?: any, index?: number, column?: IColumn) { let self = this; let fieldContent = item[column.fieldName]; switch (column.key) { - case 'firstUtterance': + case 'firstInput': return {this.firstUtterance(item)}; - case 'lastUtterance': + case 'lastInput': return {this.lastUtterance(item)}; + case 'lastResponse': + return {this.lastResponse(item)}; case 'turns': return {item.rounds.length}; default: @@ -144,6 +173,7 @@ const mapStateToProps = (state: State) => { return { userKey: state.user.key, apps: state.apps, + actions: state.actions, trainDialogs: state.trainDialogs, teachSessions: state.teachSessions } diff --git a/src/epics/apiHelpers.ts b/src/epics/apiHelpers.ts index 43d2ecec..cc678a20 100644 --- a/src/epics/apiHelpers.ts +++ b/src/epics/apiHelpers.ts @@ -7,11 +7,12 @@ import { UserInput, TrainDialog, LogDialog, TrainExtractorStep, ExtractResponse, TrainScorerStep, - Session, Teach, UIExtractResponse, UIScoreResponse, UIScoreInput + Session, Teach, + UIExtractResponse, UIScoreResponse, UIScoreInput } from 'blis-models' import * as Rx from 'rxjs'; import { Observable, Observer } from 'rxjs' -import { fetchApplicationsFulfilled, fetchAllEntitiesFulfilled, fetchAllActionsFulfilled, fetchAllChatSessionsFulfilled, fetchAllTeachSessionsFulfilled, fetchAllTrainDialogsFulfilled, fetchAllLogDialogsFulfilled } from '../actions/fetchActions' +import { fetchBotInfoFulfilled, fetchApplicationsFulfilled, fetchAllEntitiesFulfilled, fetchAllActionsFulfilled, fetchAllChatSessionsFulfilled, fetchAllTeachSessionsFulfilled, fetchAllTrainDialogsFulfilled, fetchAllLogDialogsFulfilled } from '../actions/fetchActions' import { createApplicationFulfilled, createEntityFulfilled, createPositiveEntityFulfilled, createNegativeEntityFulfilled, createActionFulfilled, createChatSessionFulfilled, createTeachSessionFulfilled } from '../actions/createActions' import { deleteBLISApplicationFulfilled, deleteReverseEntityAsnyc, deleteEntityFulfilled, deleteActionFulfilled, deleteChatSessionFulfilled, deleteTeachSessionFulfilled, deleteLogDialogFulFilled, deleteTrainDialogFulfilled } from '../actions/deleteActions' import { editBLISApplicationFulfilled, editEntityFulfilled, editActionFulfilled } from '../actions/updateActions' @@ -72,6 +73,16 @@ const makeRoute = (key: string, actionRoute : string, qstring? : string) => // GET ROUTES //========================================================= + export const getBotInfo = (key : string): Observable => { + const getBotRoute: string = makeRoute(key, `bot`); + return Rx.Observable.create((obs : Rx.Observer) => axios.get(getBotRoute, config) + .then(response => { + obs.next(fetchBotInfoFulfilled(response.data)); + obs.complete(); + }) + .catch(err => handleError(obs, err, AT.FETCH_BOTINFO_ASYNC))); + }; + export const getAllBlisApps = (key : string, userId : string): Observable => { const getAppsRoute: string = makeRoute(key, `apps`, `userId=${userId}`); return Rx.Observable.create((obs : Rx.Observer) => axios.get(getAppsRoute, config) diff --git a/src/epics/fetchEpics.ts b/src/epics/fetchEpics.ts index afa19e53..8b8baa5f 100644 --- a/src/epics/fetchEpics.ts +++ b/src/epics/fetchEpics.ts @@ -4,10 +4,16 @@ import { ActionsObservable, Epic } from 'redux-observable' import { State, ActionObject } from '../types' import { AT } from '../types/ActionTypes' import { BlisAppBase, BlisAppMetaData, BlisAppList, EntityBase, EntityMetaData, EntityList, ActionBase, ActionMetaData, ActionList, ActionTypes } from 'blis-models'; -import { getAllBlisApps, getAllEntitiesForBlisApp, getAllActionsForBlisApp, getAllSessionsForBlisApp, getAllTeachSessionsForBlisApp, getAllTrainDialogsForBlisApp, getAllLogDialogsForBlisApp } from "./apiHelpers"; +import { getBotInfo, getAllBlisApps, getAllEntitiesForBlisApp, getAllActionsForBlisApp, getAllSessionsForBlisApp, getAllTeachSessionsForBlisApp, getAllTrainDialogsForBlisApp, getAllLogDialogsForBlisApp } from "./apiHelpers"; import { fetchApplicationsFulfilled, fetchAllEntitiesFulfilled, fetchAllActionsFulfilled } from '../actions/fetchActions' import { setErrorDisplay } from '../actions/displayActions' +export const fetchBotInfoEpic: Epic = (action$: ActionsObservable): Rx.Observable => { + return action$.ofType(AT.FETCH_BOTINFO_ASYNC) + .flatMap((action: any) => + getBotInfo(action.key)); +} + export const fetchApplicationsEpic: Epic = (action$: ActionsObservable): Rx.Observable => { return action$.ofType(AT.FETCH_APPLICATIONS_ASYNC) .flatMap((action: any) => diff --git a/src/epics/root.ts b/src/epics/root.ts index 7507eb53..d84d7d32 100644 --- a/src/epics/root.ts +++ b/src/epics/root.ts @@ -2,7 +2,7 @@ import 'rxjs'; import * as Rx from 'rxjs'; import { combineEpics, ActionsObservable, Epic } from 'redux-observable' import { State, ActionObject } from '../types' -import { fetchApplicationsEpic, fetchEntitiesEpic, fetchActionsEpic, fetchChatSessionsEpic, fetchTeachSessionsEpic, fetchTrainDialogsEpic, fetchLogDialogsEpic } from './fetchEpics' +import { fetchApplicationsEpic, fetchBotInfoEpic, fetchEntitiesEpic, fetchActionsEpic, fetchChatSessionsEpic, fetchTeachSessionsEpic, fetchTrainDialogsEpic, fetchLogDialogsEpic } from './fetchEpics' import { createNewApplicationEpic, createNewEntityEpic, createNewActionEpic, createNegativeEntity, createNewChatSessionEpic, createNewTeachSessionEpic } from './createEpics' import { deleteActionEpic, deleteApplicationEpic, deleteEntityEpic, deleteTrainDialogEpic, deleteLogDialogEpic, deleteReverseEntityEpic, deleteSessionEpic, deleteTeachEpic } from './deleteEpics' import { editActionEpic, editApplicationEpic, editEntityEpic, setBlisApplicationEpic } from './updateEpics' @@ -10,6 +10,7 @@ import { runExtractorEpic, runScorerEpic, scorerFeedbackEpic, postScoreFeedbackF const rootEpic = combineEpics( fetchApplicationsEpic, + fetchBotInfoEpic, fetchEntitiesEpic, fetchActionsEpic, fetchTrainDialogsEpic, diff --git a/src/reducers/botReducer.ts b/src/reducers/botReducer.ts new file mode 100644 index 00000000..623ccd80 --- /dev/null +++ b/src/reducers/botReducer.ts @@ -0,0 +1,19 @@ +import { BotState } from '../types' +import { AT } from '../types/ActionTypes' +import { ActionObject } from '../types' +import { BotInfo } from 'blis-models'; +import { Reducer } from 'redux' + +const initialState: BotState = { + botInfo: null +}; + +const botReducer: Reducer = (state = initialState, action: ActionObject) => { + switch (action.type) { + case AT.FETCH_BOTINFO_FULFILLED: + return { ...state, botInfo: action.botInfo }; + default: + return state; + } +} +export default botReducer; \ No newline at end of file diff --git a/src/reducers/displayReducer.ts b/src/reducers/displayReducer.ts index 6c36a2e1..64168075 100644 --- a/src/reducers/displayReducer.ts +++ b/src/reducers/displayReducer.ts @@ -42,6 +42,7 @@ const displayReducer: Reducer = (state = initialState, action: Ac // If I fail to load critical data, return to home page switch (action.route) { case AT.FETCH_APPLICATIONS_ASYNC : + case AT.FETCH_BOTINFO_ASYNC: case AT.FETCH_ENTITIES_ASYNC: case AT.FETCH_ACTIONS_ASYNC: return {...initialState, displayLogin: false, displaySpinner: []}; @@ -65,6 +66,7 @@ const displayReducer: Reducer = (state = initialState, action: Ac case AT.FETCH_ACTIONS_ASYNC: case AT.FETCH_APPLICATIONS_ASYNC: + case AT.FETCH_BOTINFO_ASYNC: case AT.FETCH_CHAT_SESSIONS_ASYNC: case AT.FETCH_ENTITIES_ASYNC: case AT.FETCH_TEACH_SESSIONS_ASYNC: @@ -93,6 +95,7 @@ const displayReducer: Reducer = (state = initialState, action: Ac case AT.EDIT_ENTITY_FULFILLED: case AT.FETCH_ACTIONS_FULFILLED: + case AT.FETCH_BOTINFO_FULFILLED: case AT.FETCH_APPLICATIONS_FULFILLED: case AT.FETCH_CHAT_SESSIONS_FULFILLED: case AT.FETCH_ENTITIES_FULFILLED: diff --git a/src/reducers/root.ts b/src/reducers/root.ts index c11cfb79..671e79d9 100644 --- a/src/reducers/root.ts +++ b/src/reducers/root.ts @@ -1,5 +1,6 @@ import { combineReducers, Reducer } from 'redux'; import appsReducer from './appsReducer'; +import botReducer from './botReducer'; import entitiesReducer from './entitiesReducer'; import actionsReducer from './actionsReducer'; import trainDialogsReducer from './trainDialogsReducer'; @@ -14,6 +15,7 @@ import { State } from '../types'; const rootReducer = combineReducers({ user: userReducer, apps: appsReducer, + bot: botReducer, entities: entitiesReducer, actions: actionsReducer, trainDialogs: trainDialogsReducer, diff --git a/src/types/ActionObject.ts b/src/types/ActionObject.ts index 9b853ffd..b68e4e87 100644 --- a/src/types/ActionObject.ts +++ b/src/types/ActionObject.ts @@ -1,4 +1,4 @@ -import { BlisAppBase, BlisAppMetaData, BlisAppList, +import { BlisAppBase, BlisAppMetaData, BlisAppList, BotInfo, EntityBase, EntityMetaData, EntityList, ActionBase, ActionMetaData, ActionList, ActionTypes, TrainDialog, LogDialog, Session, Teach, @@ -40,7 +40,7 @@ export type DisplayAction = { currentBLISApp: BlisAppBase, } | { type: AT.SET_CURRENT_BLIS_APP_FULFILLED, - currentBLISApp: BlisAppBase, + currentBLISApp: BlisAppBase } | { type: AT.SET_CURRENT_TRAIN_DIALOG, currentTrainDialog: TrainDialog, @@ -104,6 +104,11 @@ export type FetchAction = { type: AT.FETCH_APPLICATIONS_ASYNC, userId: string } | { + type: AT.FETCH_BOTINFO_ASYNC + } | { + type: AT.FETCH_BOTINFO_FULFILLED, + botInfo: BotInfo, + }| { type: AT.FETCH_ENTITIES_ASYNC, blisAppID: string } | { diff --git a/src/types/ActionTypes.ts b/src/types/ActionTypes.ts index b8faa11d..71ddae72 100644 --- a/src/types/ActionTypes.ts +++ b/src/types/ActionTypes.ts @@ -34,6 +34,8 @@ export enum AT { // FetchAction FETCH_APPLICATIONS_ASYNC = 'FETCH_APPLICATIONS_ASYNC', FETCH_APPLICATIONS_FULFILLED = 'FETCH_APPLICATIONS_FULFILLED', + FETCH_BOTINFO_ASYNC = 'FETCH_BOTINFO_ASYNC', + FETCH_BOTINFO_FULFILLED = 'FETCH_BOTINFO_FULFILLED', FETCH_ENTITIES_ASYNC = 'FETCH_ENTITIES_ASYNC', FETCH_ENTITIES_FULFILLED = 'FETCH_ENTITIES_FULFILLED', FETCH_ACTIONS_ASYNC = 'FETCH_ACTIONS_ASYNC', diff --git a/src/types/StateTypes.ts b/src/types/StateTypes.ts index 7ddaad70..a54f1dd5 100644 --- a/src/types/StateTypes.ts +++ b/src/types/StateTypes.ts @@ -1,4 +1,4 @@ -import { BlisAppBase, BlisAppMetaData, BlisAppList, +import { BlisAppBase, BlisAppMetaData, BlisAppList, BotInfo, EntityBase, EntityMetaData, EntityList, ActionBase, ActionMetaData, ActionList, ActionTypes, TrainDialog, LogDialog, Teach, Session, @@ -28,6 +28,9 @@ export type AppState = { all: BlisAppBase[], current: BlisAppBase } +export type BotState = { + botInfo: BotInfo +} export type TeachSessionState = { all: Teach[], current: Teach,