From 8dc7e5fc6f2d2a7ce853f935a0a84dacb8c0585f Mon Sep 17 00:00:00 2001 From: Janicki Artur Date: Fri, 31 Aug 2018 10:37:45 +0200 Subject: [PATCH] init view log with props Feature #14098 Arvados-DCO-1.1-Signed-off-by: Janicki Artur --- src/routes/routes.ts | 11 ++- .../context-menu/context-menu-actions.ts | 10 ++- src/store/navigation/navigation-action.ts | 6 +- src/store/workbench/workbench-actions.ts | 6 ++ .../action-sets/process-action-set.ts | 3 +- .../context-menu/context-menu.tsx | 3 +- .../process-log-panel/process-log-form.tsx | 49 +++++++++++++ .../process-log-main-card.tsx | 71 +++++++++++++++++++ .../process-log-panel-root.tsx | 36 ++++++++++ .../process-log-panel/process-log-panel.tsx | 57 +++++++++++++++ src/views/workbench/workbench.tsx | 3 +- 11 files changed, 248 insertions(+), 7 deletions(-) create mode 100644 src/views/process-log-panel/process-log-form.tsx create mode 100644 src/views/process-log-panel/process-log-main-card.tsx create mode 100644 src/views/process-log-panel/process-log-panel-root.tsx create mode 100644 src/views/process-log-panel/process-log-panel.tsx diff --git a/src/routes/routes.ts b/src/routes/routes.ts index 20dd1359..6901d875 100644 --- a/src/routes/routes.ts +++ b/src/routes/routes.ts @@ -8,7 +8,7 @@ import { matchPath } from 'react-router'; import { ResourceKind, RESOURCE_UUID_PATTERN, extractUuidKind } from '~/models/resource'; import { getProjectUrl } from '../models/project'; import { getCollectionUrl } from '~/models/collection'; -import { loadProject, loadFavorites, loadCollection } from '~/store/workbench/workbench-actions'; +import { loadProject, loadFavorites, loadCollection, loadProcessLog } from '~/store/workbench/workbench-actions'; import { loadProcess } from '~/store/processes/processes-actions'; export const Routes = { @@ -18,6 +18,7 @@ export const Routes = { COLLECTIONS: `/collections/:id(${RESOURCE_UUID_PATTERN})`, PROCESSES: `/processes/:id(${RESOURCE_UUID_PATTERN})`, FAVORITES: '/favorites', + PROCESS_LOGS: `/process-logs/:id(${RESOURCE_UUID_PATTERN})` }; export const getResourceUrl = (uuid: string) => { @@ -34,6 +35,8 @@ export const getResourceUrl = (uuid: string) => { export const getProcessUrl = (uuid: string) => `/processes/${uuid}`; +export const getProcessLogUrl = (uuid: string) => `/process-logs/${uuid}`; + export const addRouteChangeHandlers = (history: History, store: RootStore) => { const handler = handleLocationChange(store); handler(history.location); @@ -59,12 +62,16 @@ export const matchCollectionRoute = (route: string) => export const matchProcessRoute = (route: string) => matchPath(route, { path: Routes.PROCESSES }); +export const matchProcessLogRoute = (route: string) => + matchPath(route, { path: Routes.PROCESS_LOGS }); const handleLocationChange = (store: RootStore) => ({ pathname }: Location) => { const projectMatch = matchProjectRoute(pathname); const collectionMatch = matchCollectionRoute(pathname); const favoriteMatch = matchFavoritesRoute(pathname); const processMatch = matchProcessRoute(pathname); + const processLogMatch = matchProcessLogRoute(pathname); + if (projectMatch) { store.dispatch(loadProject(projectMatch.params.id)); } else if (collectionMatch) { @@ -73,5 +80,7 @@ const handleLocationChange = (store: RootStore) => ({ pathname }: Location) => { store.dispatch(loadFavorites()); } else if (processMatch) { store.dispatch(loadProcess(processMatch.params.id)); + } else if (processLogMatch) { + store.dispatch(loadProcessLog(processLogMatch.params.id)); } }; diff --git a/src/store/context-menu/context-menu-actions.ts b/src/store/context-menu/context-menu-actions.ts index cf66a53d..3440a305 100644 --- a/src/store/context-menu/context-menu-actions.ts +++ b/src/store/context-menu/context-menu-actions.ts @@ -12,6 +12,7 @@ import { ProjectResource } from '~/models/project'; import { UserResource } from '../../models/user'; import { isSidePanelTreeCategory } from '~/store/side-panel-tree/side-panel-tree-actions'; import { extractUuidKind, ResourceKind } from '~/models/resource'; +import { matchProcessRoute } from '~/routes/routes'; export const contextMenuActions = unionize({ OPEN_CONTEXT_MENU: ofType<{ position: ContextMenuPosition, resource: ContextMenuResource }>(), @@ -69,8 +70,15 @@ export const openSidePanelContextMenu = (event: React.MouseEvent, i export const openProcessContextMenu = (event: React.MouseEvent) => (dispatch: Dispatch, getState: () => RootState) => { + const { location } = getState().router; + const pathname = location ? location.pathname : ''; + // ToDo: We get error from matchProcessRoute + // const match = matchProcessRoute(pathname); + // console.log('match: ', match); + // const uuid = match ? match.params.id : ''; + const uuid = pathname.split('/').slice(-1)[0]; const resource = { - uuid: '', + uuid, name: '', description: '', kind: ContextMenuKind.PROCESS diff --git a/src/store/navigation/navigation-action.ts b/src/store/navigation/navigation-action.ts index 188acf12..6298e251 100644 --- a/src/store/navigation/navigation-action.ts +++ b/src/store/navigation/navigation-action.ts @@ -9,7 +9,7 @@ import { getCollectionUrl } from "~/models/collection"; import { getProjectUrl } from "~/models/project"; import { SidePanelTreeCategory } from '../side-panel-tree/side-panel-tree-actions'; -import { Routes, getProcessUrl } from '~/routes/routes'; +import { Routes, getProcessUrl, getProcessLogUrl } from '~/routes/routes'; export const navigateTo = (uuid: string) => async (dispatch: Dispatch) => { @@ -20,7 +20,7 @@ export const navigateTo = (uuid: string) => dispatch(navigateToCollection(uuid)); } else if (kind === ResourceKind.CONTAINER_REQUEST) { dispatch(navigateToProcess(uuid)); - } + } if (uuid === SidePanelTreeCategory.FAVORITES) { dispatch(navigateToFavorites); } @@ -33,3 +33,5 @@ export const navigateToProject = compose(push, getProjectUrl); export const navigateToCollection = compose(push, getCollectionUrl); export const navigateToProcess = compose(push, getProcessUrl); + +export const navigateToProcessLogs = compose(push, getProcessLogUrl); \ No newline at end of file diff --git a/src/store/workbench/workbench-actions.ts b/src/store/workbench/workbench-actions.ts index 3c68c000..97fe549a 100644 --- a/src/store/workbench/workbench-actions.ts +++ b/src/store/workbench/workbench-actions.ts @@ -185,6 +185,12 @@ export const loadProcess = (uuid: string) => } }; +export const loadProcessLog = (uuid: string) => + async (dispatch: Dispatch, getState: () => RootState) => { + dispatch(loadProcess(uuid)); + // ToDo: loadLog(); + }; + export const resourceIsNotLoaded = (uuid: string) => snackbarActions.OPEN_SNACKBAR({ message: `Resource identified by ${uuid} is not loaded.` diff --git a/src/views-components/context-menu/action-sets/process-action-set.ts b/src/views-components/context-menu/action-sets/process-action-set.ts index 5d679f52..cc4f8e8f 100644 --- a/src/views-components/context-menu/action-sets/process-action-set.ts +++ b/src/views-components/context-menu/action-sets/process-action-set.ts @@ -10,6 +10,7 @@ import { AdvancedIcon, RemoveIcon, ReRunProcessIcon, LogIcon } from "~/components/icon/icon"; import { favoritePanelActions } from "~/store/favorite-panel/favorite-panel-action"; +import { navigateToProcessLogs } from '~/store/navigation/navigation-action'; export const processActionSet: ContextMenuActionSet = [[ { @@ -84,7 +85,7 @@ export const processActionSet: ContextMenuActionSet = [[ icon: LogIcon, name: "Log", execute: (dispatch, resource) => { - // add code + dispatch(navigateToProcessLogs(resource.uuid)); } }, { diff --git a/src/views-components/context-menu/context-menu.tsx b/src/views-components/context-menu/context-menu.tsx index 5d94766c..d92948c8 100644 --- a/src/views-components/context-menu/context-menu.tsx +++ b/src/views-components/context-menu/context-menu.tsx @@ -64,5 +64,6 @@ export enum ContextMenuKind { COLLECTION_FILES_ITEM = "CollectionFilesItem", COLLECTION = 'Collection', COLLECTION_RESOURCE = 'CollectionResource', - PROCESS = "Process" + PROCESS = "Process", + PROCESS_LOGS = "ProcessLogs" } diff --git a/src/views/process-log-panel/process-log-form.tsx b/src/views/process-log-panel/process-log-form.tsx new file mode 100644 index 00000000..dfac832f --- /dev/null +++ b/src/views/process-log-panel/process-log-form.tsx @@ -0,0 +1,49 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import * as React from 'react'; +import { withStyles, WithStyles, StyleRulesCallback, FormControl, InputLabel, Select, MenuItem, Input } from '@material-ui/core'; +import { ArvadosTheme } from '~/common/custom-theme'; +import { FilterOption } from './process-log-panel'; + +type CssRules = 'formControl'; + +const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ + formControl: { + minWidth: 200 + } +}); + +export interface ProcessLogFormDataProps { + selectedFilter: FilterOption; + filters: FilterOption[]; +} + +export interface ProcessLogFormActionProps { + onChange: (filter: FilterOption) => void; +} + +type ProcessLogFormProps = ProcessLogFormDataProps & ProcessLogFormActionProps & WithStyles; + +export const ProcessLogForm = withStyles(styles)( + ({ classes, selectedFilter, onChange, filters }: ProcessLogFormProps) => +
+ + + Log + + } + name="eventType"> + { + filters.map(option => + {option.label} + ) + } + + +
+); \ No newline at end of file diff --git a/src/views/process-log-panel/process-log-main-card.tsx b/src/views/process-log-panel/process-log-main-card.tsx new file mode 100644 index 00000000..db451ab9 --- /dev/null +++ b/src/views/process-log-panel/process-log-main-card.tsx @@ -0,0 +1,71 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import * as React from 'react'; +import { + StyleRulesCallback, WithStyles, withStyles, Card, + CardHeader, IconButton, CardContent, Grid, Typography, Tooltip +} from '@material-ui/core'; +import { Process } from '~/store/processes/process'; +import { ProcessLogForm, ProcessLogFormDataProps, ProcessLogFormActionProps } from '~/views/process-log-panel/process-log-form'; +import { MoreOptionsIcon, ProcessIcon } from '~/components/icon/icon'; +import { ArvadosTheme } from '~/common/custom-theme'; + +type CssRules = 'root' | 'card' | 'iconHeader'; + +const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ + root: { + + }, + card: { + width: '100%' + }, + iconHeader: { + fontSize: '1.875rem', + color: theme.customs.colors.green700 + } +}); + + +interface ProcessLogMainCardDataProps { + process: Process; +} + +export type ProcessLogMainCardProps = ProcessLogMainCardDataProps & ProcessLogFormDataProps & ProcessLogFormActionProps; + +export const ProcessLogMainCard = withStyles(styles)( + ({ classes, process, selectedFilter, filters, onChange }: ProcessLogMainCardProps & WithStyles) => + + } + action={ +
+ + + +
+ } + title={ + + + {process.containerRequest.name} + + + } + subheader={process.containerRequest.description} /> + + + + + + + Container log for request ardev-xvhdp-q3uqbfxeb6w64pm + + + {/* add snippet */} + + + +
+); \ No newline at end of file diff --git a/src/views/process-log-panel/process-log-panel-root.tsx b/src/views/process-log-panel/process-log-panel-root.tsx new file mode 100644 index 00000000..fe8a5b18 --- /dev/null +++ b/src/views/process-log-panel/process-log-panel-root.tsx @@ -0,0 +1,36 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import * as React from 'react'; +import { Grid } from '@material-ui/core'; +import { Process } from '~/store/processes/process'; +import { ProcessLogMainCard } from '~/views/process-log-panel/process-log-main-card'; +import { ProcessLogFormDataProps, ProcessLogFormActionProps } from '~/views/process-log-panel/process-log-form'; +import { DefaultView } from '~/components/default-view/default-view'; +import { ProcessIcon } from '~/components/icon/icon'; + +export type ProcessLogPanelRootDataProps = { + process?: Process; +} & ProcessLogFormDataProps; + +export type ProcessLogPanelRootActionProps = { + onContextMenu: (event: React.MouseEvent) => void; +} & ProcessLogFormActionProps; + +export type ProcessLogPanelRootProps = ProcessLogPanelRootDataProps & ProcessLogPanelRootActionProps; + +export const ProcessLogPanelRoot = (props: ProcessLogPanelRootProps) => + props.process + ? + + + : + + ; diff --git a/src/views/process-log-panel/process-log-panel.tsx b/src/views/process-log-panel/process-log-panel.tsx new file mode 100644 index 00000000..1ce06afd --- /dev/null +++ b/src/views/process-log-panel/process-log-panel.tsx @@ -0,0 +1,57 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import * as React from 'react'; +import { RootState } from '~/store/store'; +import { connect } from 'react-redux'; +import { getProcess } from '~/store/processes/process'; +import { Dispatch } from 'redux'; +import { openProcessContextMenu } from '~/store/context-menu/context-menu-actions'; +import { matchProcessLogRoute } from '~/routes/routes'; +import { ProcessLogPanelRootDataProps, ProcessLogPanelRootActionProps, ProcessLogPanelRoot } from './process-log-panel-root'; + +const SELECT_OPTIONS = [ + { label: 'Dispatch', value: 'dispatch' }, + { label: 'Crunch-run', value: 'crunch-run' }, + { label: 'Crunchstat', value: 'crunchstat' }, + { label: 'Hoststat', value: 'hoststat' }, + { label: 'Node-info', value: 'node-info' }, + { label: 'Arv-mount', value: 'arv-mount' }, + { label: 'Stdout', value: 'stdout' }, + { label: 'Stderr', value: 'stderr' } +]; + +export interface Log { + object_uuid: string; + event_at: string; + event_type: string; + summary: string; + properties: any; +} + +export interface FilterOption { + label: string; + value: string; +} + +const mapStateToProps = ({ router, resources }: RootState): ProcessLogPanelRootDataProps => { + const pathname = router.location ? router.location.pathname : ''; + const match = matchProcessLogRoute(pathname); + const uuid = match ? match.params.id : ''; + return { + process: getProcess(uuid)(resources), + selectedFilter: SELECT_OPTIONS[0], + filters: SELECT_OPTIONS + // lines: string[] + }; +}; + +const mapDispatchToProps = (dispatch: Dispatch): ProcessLogPanelRootActionProps => ({ + onContextMenu: (event: React.MouseEvent) => { + dispatch(openProcessContextMenu(event)); + }, + onChange: (filter: FilterOption) => { return; } +}); + +export const ProcessLogPanel = connect(mapStateToProps, mapDispatchToProps)(ProcessLogPanelRoot); diff --git a/src/views/workbench/workbench.tsx b/src/views/workbench/workbench.tsx index ef5fe215..21396d1d 100644 --- a/src/views/workbench/workbench.tsx +++ b/src/views/workbench/workbench.tsx @@ -27,6 +27,7 @@ import { MultipleFilesRemoveDialog } from '~/views-components/file-remove-dialog import { Routes } from '~/routes/routes'; import { SidePanel } from '~/views-components/side-panel/side-panel'; import { ProcessPanel } from '~/views/process-panel/process-panel'; +import { ProcessLogPanel } from '~/views/process-log-panel/process-log-panel'; import { Breadcrumbs } from '~/views-components/breadcrumbs/breadcrumbs'; import { CreateProjectDialog } from '~/views-components/dialog-forms/create-project-dialog'; import { CreateCollectionDialog } from '~/views-components/dialog-forms/create-collection-dialog'; @@ -35,7 +36,6 @@ import { UpdateCollectionDialog } from '~/views-components/dialog-forms/update-c import { UpdateProjectDialog } from '~/views-components/dialog-forms/update-project-dialog'; import { MoveProjectDialog } from '~/views-components/dialog-forms/move-project-dialog'; import { MoveCollectionDialog } from '~/views-components/dialog-forms/move-collection-dialog'; - import { FilesUploadCollectionDialog } from '~/views-components/dialog-forms/files-upload-collection-dialog'; import { PartialCopyCollectionDialog } from '~/views-components/dialog-forms/partial-copy-collection-dialog'; @@ -167,6 +167,7 @@ export const Workbench = withStyles(styles)( + {user && } -- 2.30.2