[ARVADOS-WORKBENCH2] created: 1.3.0-120-gca091db
Git user
git at public.curoverse.com
Thu Dec 13 10:32:54 EST 2018
at ca091dbfbc7df1a3f81eca2b16925b3225d43138 (commit)
commit ca091dbfbc7df1a3f81eca2b16925b3225d43138
Author: Janicki Artur <artur.janicki at contractors.roche.com>
Date: Thu Dec 13 16:32:40 2018 +0100
refactor link panel
Feature #14602_admin_compute_node_paginations
Arvados-DCO-1.1-Signed-off-by: Janicki Artur <artur.janicki at contractors.roche.com>
diff --git a/src/views/link-panel/link-panel-root.tsx b/src/views/link-panel/link-panel-root.tsx
index d5ba79b..a4c8e01 100644
--- a/src/views/link-panel/link-panel-root.tsx
+++ b/src/views/link-panel/link-panel-root.tsx
@@ -63,19 +63,19 @@ export const linkPanelColumns: DataColumns<string> = [
}
];
-export interface LinkPanelDataProps {
+export interface LinkPanelRootDataProps {
resources: ResourcesState;
}
-export interface LinkPanelActionProps {
+export interface LinkPanelRootActionProps {
onItemClick: (item: string) => void;
onContextMenu: (event: React.MouseEvent<HTMLElement>, item: string) => void;
onItemDoubleClick: (item: string) => void;
}
-export type LinkPanelProps = LinkPanelDataProps & LinkPanelActionProps;
+export type LinkPanelRootProps = LinkPanelRootDataProps & LinkPanelRootActionProps;
-export const LinkPanelRoot = (props: LinkPanelProps) => {
+export const LinkPanelRoot = (props: LinkPanelRootProps) => {
return <DataExplorer
id={LINK_PANEL_ID}
onRowClick={props.onItemClick}
diff --git a/src/views/link-panel/link-panel.tsx b/src/views/link-panel/link-panel.tsx
index 2c3bf75..4bff4ee 100644
--- a/src/views/link-panel/link-panel.tsx
+++ b/src/views/link-panel/link-panel.tsx
@@ -6,16 +6,16 @@ import { Dispatch } from "redux";
import { connect } from "react-redux";
import { RootState } from '~/store/store';
import { openContextMenu, resourceKindToContextMenuKind } from '~/store/context-menu/context-menu-actions';
-import { LinkPanelRoot, LinkPanelActionProps } from '~/views/link-panel/link-panel-root';
+import { LinkPanelRoot, LinkPanelRootActionProps, LinkPanelRootDataProps } from '~/views/link-panel/link-panel-root';
import { ResourceKind } from '~/models/resource';
-const mapStateToProps = (state: RootState) => {
+const mapStateToProps = (state: RootState): LinkPanelRootDataProps => {
return {
resources: state.resources
};
};
-const mapDispatchToProps = (dispatch: Dispatch): LinkPanelActionProps => ({
+const mapDispatchToProps = (dispatch: Dispatch): LinkPanelRootActionProps => ({
onContextMenu: (event, resourceUuid) => {
const kind = resourceKindToContextMenuKind(resourceUuid);
if (kind) {
commit 8278f352297c404e9200c92d22dce05b20ad12bc
Author: Janicki Artur <artur.janicki at contractors.roche.com>
Date: Thu Dec 13 16:32:28 2018 +0100
add compute node middleware, data explorer and remove reducer
Feature #14602_admin_compute_node_paginations
Arvados-DCO-1.1-Signed-off-by: Janicki Artur <artur.janicki at contractors.roche.com>
diff --git a/src/store/advanced-tab/advanced-tab.ts b/src/store/advanced-tab/advanced-tab.ts
index 659b6e4..da3f5c9 100644
--- a/src/store/advanced-tab/advanced-tab.ts
+++ b/src/store/advanced-tab/advanced-tab.ts
@@ -241,7 +241,8 @@ export const openAdvancedTabDialog = (uuid: string) =>
dispatch<any>(initAdvancedTabDialog(advanceDataUser));
break;
case ResourceKind.NODE:
- const dataComputeNode = getState().computeNodes.find(node => node.uuid === uuid);
+ const computeNodeResources = getState().resources;
+ const dataComputeNode = getResource<NodeResource>(uuid)(computeNodeResources);
const advanceDataComputeNode = advancedTabData({
uuid,
metadata: '',
diff --git a/src/store/compute-nodes/compute-nodes-actions.ts b/src/store/compute-nodes/compute-nodes-actions.ts
index 659b1e8..f2f6ad0 100644
--- a/src/store/compute-nodes/compute-nodes-actions.ts
+++ b/src/store/compute-nodes/compute-nodes-actions.ts
@@ -3,21 +3,18 @@
// SPDX-License-Identifier: AGPL-3.0
import { Dispatch } from "redux";
-import { unionize, ofType, UnionOf } from "~/common/unionize";
import { RootState } from '~/store/store';
import { setBreadcrumbs } from '~/store/breadcrumbs/breadcrumbs-actions';
-import { ServiceRepository } from "~/services/services";
-import { NodeResource } from '~/models/node';
import { dialogActions } from '~/store/dialog/dialog-actions';
import { snackbarActions } from '~/store/snackbar/snackbar-actions';
import { navigateToRootProject } from '~/store/navigation/navigation-action';
+import { bindDataExplorerActions } from '~/store/data-explorer/data-explorer-action';
+import { getResource } from '~/store/resources/resources';
+import { ServiceRepository } from "~/services/services";
+import { NodeResource } from '~/models/node';
-export const computeNodesActions = unionize({
- SET_COMPUTE_NODES: ofType<NodeResource[]>(),
- REMOVE_COMPUTE_NODE: ofType<string>()
-});
-
-export type ComputeNodesActions = UnionOf<typeof computeNodesActions>;
+export const COMPUTE_NODE_PANEL_ID = "computeNodeId";
+export const computeNodesActions = bindDataExplorerActions(COMPUTE_NODE_PANEL_ID);
export const COMPUTE_NODE_REMOVE_DIALOG = 'computeNodeRemoveDialog';
export const COMPUTE_NODE_ATTRIBUTES_DIALOG = 'computeNodeAttributesDialog';
@@ -28,8 +25,7 @@ export const loadComputeNodesPanel = () =>
if (user && user.isAdmin) {
try {
dispatch(setBreadcrumbs([{ label: 'Compute Nodes' }]));
- const response = await services.nodeService.list();
- dispatch(computeNodesActions.SET_COMPUTE_NODES(response.items));
+ dispatch(computeNodesActions.REQUEST_ITEMS());
} catch (e) {
return;
}
@@ -41,7 +37,8 @@ export const loadComputeNodesPanel = () =>
export const openComputeNodeAttributesDialog = (uuid: string) =>
(dispatch: Dispatch, getState: () => RootState) => {
- const computeNode = getState().computeNodes.find(node => node.uuid === uuid);
+ const { resources } = getState();
+ const computeNode = getResource<NodeResource>(uuid)(resources);
dispatch(dialogActions.OPEN_DIALOG({ id: COMPUTE_NODE_ATTRIBUTES_DIALOG, data: { computeNode } }));
};
@@ -63,7 +60,7 @@ export const removeComputeNode = (uuid: string) =>
dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Removing ...' }));
try {
await services.nodeService.delete(uuid);
- dispatch(computeNodesActions.REMOVE_COMPUTE_NODE(uuid));
+ dispatch(computeNodesActions.REQUEST_ITEMS());
dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Compute node has been successfully removed.', hideDuration: 2000 }));
} catch (e) {
return;
diff --git a/src/store/compute-nodes/compute-nodes-middleware-service.ts b/src/store/compute-nodes/compute-nodes-middleware-service.ts
new file mode 100644
index 0000000..792da7a
--- /dev/null
+++ b/src/store/compute-nodes/compute-nodes-middleware-service.ts
@@ -0,0 +1,70 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { ServiceRepository } from '~/services/services';
+import { MiddlewareAPI, Dispatch } from 'redux';
+import { DataExplorerMiddlewareService, dataExplorerToListParams, listResultsToDataExplorerItemsMeta } from '~/store/data-explorer/data-explorer-middleware-service';
+import { RootState } from '~/store/store';
+import { snackbarActions, SnackbarKind } from '~/store/snackbar/snackbar-actions';
+import { DataExplorer, getDataExplorer } from '~/store/data-explorer/data-explorer-reducer';
+import { updateResources } from '~/store/resources/resources-actions';
+import { getSortColumn } from "~/store/data-explorer/data-explorer-reducer";
+import { computeNodesActions } from '~/store/compute-nodes/compute-nodes-actions';
+import { OrderDirection, OrderBuilder } from '~/services/api/order-builder';
+import { ListResults } from '~/services/common-service/common-service';
+import { NodeResource } from '~/models/node';
+import { SortDirection } from '~/components/data-table/data-column';
+import { ComputeNodePanelColumnNames } from '~/views/compute-node-panel/compute-node-panel-root';
+
+export class ComputeNodeMiddlewareService extends DataExplorerMiddlewareService {
+ constructor(private services: ServiceRepository, id: string) {
+ super(id);
+ }
+
+ async requestItems(api: MiddlewareAPI<Dispatch, RootState>) {
+ const state = api.getState();
+ const dataExplorer = getDataExplorer(state.dataExplorer, this.getId());
+ try {
+ const response = await this.services.nodeService.list(getParams(dataExplorer));
+ api.dispatch(updateResources(response.items));
+ api.dispatch(setItems(response));
+ } catch {
+ api.dispatch(couldNotFetchLinks());
+ }
+ }
+}
+
+export const getParams = (dataExplorer: DataExplorer) => ({
+ ...dataExplorerToListParams(dataExplorer),
+ order: getOrder(dataExplorer)
+});
+
+const getOrder = (dataExplorer: DataExplorer) => {
+ const sortColumn = getSortColumn(dataExplorer);
+ const order = new OrderBuilder<NodeResource>();
+ if (sortColumn) {
+ const sortDirection = sortColumn && sortColumn.sortDirection === SortDirection.ASC
+ ? OrderDirection.ASC
+ : OrderDirection.DESC;
+
+ const columnName = sortColumn && sortColumn.name === ComputeNodePanelColumnNames.UUID ? "uuid" : "modifiedAt";
+ return order
+ .addOrder(sortDirection, columnName)
+ .getOrder();
+ } else {
+ return order.getOrder();
+ }
+};
+
+export const setItems = (listResults: ListResults<NodeResource>) =>
+ computeNodesActions.SET_ITEMS({
+ ...listResultsToDataExplorerItemsMeta(listResults),
+ items: listResults.items.map(resource => resource.uuid),
+ });
+
+const couldNotFetchLinks = () =>
+ snackbarActions.OPEN_SNACKBAR({
+ message: 'Could not fetch compute nodes.',
+ kind: SnackbarKind.ERROR
+ });
diff --git a/src/store/compute-nodes/compute-nodes-reducer.ts b/src/store/compute-nodes/compute-nodes-reducer.ts
deleted file mode 100644
index 44a3780..0000000
--- a/src/store/compute-nodes/compute-nodes-reducer.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (C) The Arvados Authors. All rights reserved.
-//
-// SPDX-License-Identifier: AGPL-3.0
-
-import { computeNodesActions, ComputeNodesActions } from '~/store/compute-nodes/compute-nodes-actions';
-import { NodeResource } from '~/models/node';
-
-export type ComputeNodesState = NodeResource[];
-
-const initialState: ComputeNodesState = [];
-
-export const computeNodesReducer = (state: ComputeNodesState = initialState, action: ComputeNodesActions): ComputeNodesState =>
- computeNodesActions.match(action, {
- SET_COMPUTE_NODES: nodes => nodes,
- REMOVE_COMPUTE_NODE: (uuid: string) => state.filter((computeNode) => computeNode.uuid !== uuid),
- default: () => state
- });
\ No newline at end of file
diff --git a/src/store/context-menu/context-menu-actions.ts b/src/store/context-menu/context-menu-actions.ts
index e9b08a8..6a5e7b7 100644
--- a/src/store/context-menu/context-menu-actions.ts
+++ b/src/store/context-menu/context-menu-actions.ts
@@ -17,7 +17,6 @@ import { RepositoryResource } from '~/models/repositories';
import { SshKeyResource } from '~/models/ssh-key';
import { VirtualMachinesResource } from '~/models/virtual-machines';
import { KeepServiceResource } from '~/models/keep-services';
-import { NodeResource } from '~/models/node';
import { ApiClientAuthorization } from '~/models/api-client-authorization';
export const contextMenuActions = unionize({
@@ -111,12 +110,12 @@ export const openKeepServiceContextMenu = (event: React.MouseEvent<HTMLElement>,
}));
};
-export const openComputeNodeContextMenu = (event: React.MouseEvent<HTMLElement>, computeNode: NodeResource) =>
+export const openComputeNodeContextMenu = (event: React.MouseEvent<HTMLElement>, resourceUuid: string) =>
(dispatch: Dispatch) => {
dispatch<any>(openContextMenu(event, {
name: '',
- uuid: computeNode.uuid,
- ownerUuid: computeNode.ownerUuid,
+ uuid: resourceUuid,
+ ownerUuid: '',
kind: ResourceKind.NODE,
menuKind: ContextMenuKind.NODE
}));
diff --git a/src/store/link-panel/link-panel-actions.ts b/src/store/link-panel/link-panel-actions.ts
index 944c1bd..7cbc507 100644
--- a/src/store/link-panel/link-panel-actions.ts
+++ b/src/store/link-panel/link-panel-actions.ts
@@ -18,6 +18,12 @@ export const linkPanelActions = bindDataExplorerActions(LINK_PANEL_ID);
export const LINK_REMOVE_DIALOG = 'linkRemoveDialog';
export const LINK_ATTRIBUTES_DIALOG = 'linkAttributesDialog';
+export const loadLinkPanel = () =>
+ (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ dispatch(setBreadcrumbs([{ label: 'Links' }]));
+ dispatch(linkPanelActions.REQUEST_ITEMS());
+ };
+
export const openLinkAttributesDialog = (uuid: string) =>
(dispatch: Dispatch, getState: () => RootState) => {
const { resources } = getState();
@@ -38,12 +44,6 @@ export const openLinkRemoveDialog = (uuid: string) =>
}));
};
-export const loadLinkPanel = () =>
- (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
- dispatch(setBreadcrumbs([{ label: 'Links' }]));
- dispatch(linkPanelActions.REQUEST_ITEMS());
- };
-
export const removeLink = (uuid: string) =>
async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Removing ...' }));
diff --git a/src/store/store.ts b/src/store/store.ts
index 792224d..d196e63 100644
--- a/src/store/store.ts
+++ b/src/store/store.ts
@@ -48,10 +48,11 @@ import { repositoriesReducer } from '~/store/repositories/repositories-reducer';
import { keepServicesReducer } from '~/store/keep-services/keep-services-reducer';
import { UserMiddlewareService } from '~/store/users/user-panel-middleware-service';
import { USERS_PANEL_ID } from '~/store/users/users-actions';
-import { computeNodesReducer } from '~/store/compute-nodes/compute-nodes-reducer';
import { apiClientAuthorizationsReducer } from '~/store/api-client-authorizations/api-client-authorizations-reducer';
import { LINK_PANEL_ID } from '~/store/link-panel/link-panel-actions';
import { LinkMiddlewareService } from '~/store/link-panel/link-panel-middleware-service';
+import { COMPUTE_NODE_PANEL_ID } from '~/store/compute-nodes/compute-nodes-actions';
+import { ComputeNodeMiddlewareService } from '~/store/compute-nodes/compute-nodes-middleware-service';
const composeEnhancers =
(process.env.NODE_ENV === 'development' &&
@@ -89,6 +90,9 @@ export function configureStore(history: History, services: ServiceRepository): R
const linkPanelMiddleware = dataExplorerMiddleware(
new LinkMiddlewareService(services, LINK_PANEL_ID)
);
+ const computeNodeMiddleware = dataExplorerMiddleware(
+ new ComputeNodeMiddlewareService(services, COMPUTE_NODE_PANEL_ID)
+ );
const middlewares: Middleware[] = [
routerMiddleware(history),
thunkMiddleware.withExtraArgument(services),
@@ -99,7 +103,8 @@ export function configureStore(history: History, services: ServiceRepository): R
sharedWithMePanelMiddleware,
workflowPanelMiddleware,
userPanelMiddleware,
- linkPanelMiddleware
+ linkPanelMiddleware,
+ computeNodeMiddleware
];
const enhancer = composeEnhancers(applyMiddleware(...middlewares));
return createStore(rootReducer, enhancer);
@@ -131,6 +136,5 @@ const createRootReducer = (services: ServiceRepository) => combineReducers({
virtualMachines: virtualMachinesReducer,
repositories: repositoriesReducer,
keepServices: keepServicesReducer,
- computeNodes: computeNodesReducer,
apiClientAuthorizations: apiClientAuthorizationsReducer
});
diff --git a/src/store/workbench/workbench-actions.ts b/src/store/workbench/workbench-actions.ts
index 85540f0..e42e6c3 100644
--- a/src/store/workbench/workbench-actions.ts
+++ b/src/store/workbench/workbench-actions.ts
@@ -60,9 +60,10 @@ import { loadRepositoriesPanel } from '~/store/repositories/repositories-actions
import { loadKeepServicesPanel } from '~/store/keep-services/keep-services-actions';
import { loadUsersPanel, userBindedActions } from '~/store/users/users-actions';
import { loadLinkPanel, linkPanelActions } from '~/store/link-panel/link-panel-actions';
+import { loadComputeNodesPanel, computeNodesActions } from '~/store/compute-nodes/compute-nodes-actions';
import { linkPanelColumns } from '~/views/link-panel/link-panel-root';
import { userPanelColumns } from '~/views/user-panel/user-panel';
-import { loadComputeNodesPanel } from '~/store/compute-nodes/compute-nodes-actions';
+import { computeNodePanelColumns } from '~/views/compute-node-panel/compute-node-panel-root';
import { loadApiClientAuthorizationsPanel } from '~/store/api-client-authorizations/api-client-authorizations-actions';
export const WORKBENCH_LOADING_SCREEN = 'workbenchLoadingScreen';
@@ -99,6 +100,7 @@ export const loadWorkbench = () =>
dispatch(searchResultsPanelActions.SET_COLUMNS({ columns: searchResultsPanelColumns }));
dispatch(userBindedActions.SET_COLUMNS({ columns: userPanelColumns }));
dispatch(linkPanelActions.SET_COLUMNS({ columns: linkPanelColumns }));
+ dispatch(computeNodesActions.SET_COLUMNS({ columns: computeNodePanelColumns }));
dispatch<any>(initSidePanelTree());
if (router.location) {
const match = matchRootRoute(router.location.pathname);
diff --git a/src/views-components/data-explorer/renderers.tsx b/src/views-components/data-explorer/renderers.tsx
index a4713c8..9b9a5bb 100644
--- a/src/views-components/data-explorer/renderers.tsx
+++ b/src/views-components/data-explorer/renderers.tsx
@@ -26,6 +26,8 @@ import { toggleIsActive, toggleIsAdmin } from '~/store/users/users-actions';
import { LinkResource } from '~/models/link';
import { navigateTo } from '~/store/navigation/navigation-action';
import { Link } from 'react-router-dom';
+import { NodeResource } from '../../models/node';
+import { NodeInfo } from '~/models/node';
const renderName = (item: { name: string; uuid: string, kind: string }) =>
<Grid container alignItems="center" wrap="nowrap" spacing={16}>
@@ -191,6 +193,60 @@ export const ResourceUsername = connect(
return resource || { username: '' };
})(renderUsername);
+// Compute Node Resources
+const renderNodeDate = (date?: string) =>
+ <Typography noWrap>{formatDate(date) || '(none)'}</Typography>;
+
+const renderNodeData = (property?: string) =>
+ <Typography noWrap>{property || '(none)'}</Typography>;
+
+const renderNodeInfo = (item: { info: NodeInfo }) =>
+ <Typography>
+ {JSON.stringify(item.info, null, 4)}
+ </Typography>;
+
+export const ResourceNodeInfo = connect(
+ (state: RootState, props: { uuid: string }) => {
+ const resource = getResource<NodeResource>(props.uuid)(state.resources);
+ return resource || { info: {} };
+ })(renderNodeInfo);
+
+export const ResourceNodeDomain = connect(
+ (state: RootState, props: { uuid: string }) => {
+ const resource = getResource<NodeResource>(props.uuid)(state.resources);
+ return { property: resource ? resource.domain : '' };
+ })((props: { property: string }) => renderNodeData(props.property));
+
+export const ResourceNodeFirstPingAt = connect(
+ (state: RootState, props: { uuid: string }) => {
+ const resource = getResource<NodeResource>(props.uuid)(state.resources);
+ return { date: resource ? resource.firstPingAt : '' };
+ })((props: { date: string }) => renderNodeDate(props.date));
+
+export const ResourceNodeHostname = connect(
+ (state: RootState, props: { uuid: string }) => {
+ const resource = getResource<NodeResource>(props.uuid)(state.resources);
+ return { property: resource ? resource.hostname : '' };
+ })((props: { property: string }) => renderNodeData(props.property));
+
+export const ResourceNodeIpAddress = connect(
+ (state: RootState, props: { uuid: string }) => {
+ const resource = getResource<NodeResource>(props.uuid)(state.resources);
+ return { property: resource ? resource.ipAddress : '' };
+ })((props: { property: string }) => renderNodeData(props.property));
+
+export const ResourceNodeJobUuid = connect(
+ (state: RootState, props: { uuid: string }) => {
+ const resource = getResource<NodeResource>(props.uuid)(state.resources);
+ return { property: resource ? resource.jobUuid : '' };
+ })((props: { property: string }) => renderNodeData(props.property));
+
+export const ResourceNodeLastPingAt = connect(
+ (state: RootState, props: { uuid: string }) => {
+ const resource = getResource<NodeResource>(props.uuid)(state.resources);
+ return { date: resource ? resource.lastPingAt : '' };
+ })((props: { date: string }) => renderNodeDate(props.date));
+
// Links Resources
const renderLinkName = (item: { name: string }) =>
<Typography noWrap>{item.name || '(none)'}</Typography>;
diff --git a/src/views/compute-node-panel/compute-node-panel-root.tsx b/src/views/compute-node-panel/compute-node-panel-root.tsx
index 2d325b5..1a525d8 100644
--- a/src/views/compute-node-panel/compute-node-panel-root.tsx
+++ b/src/views/compute-node-panel/compute-node-panel-root.tsx
@@ -3,83 +3,114 @@
// SPDX-License-Identifier: AGPL-3.0
import * as React from 'react';
+import { ShareMeIcon } from '~/components/icon/icon';
+import { DataExplorer } from '~/views-components/data-explorer/data-explorer';
+import { DataTableDefaultView } from '~/components/data-table-default-view/data-table-default-view';
+import { COMPUTE_NODE_PANEL_ID } from '~/store/compute-nodes/compute-nodes-actions';
+import { DataColumns } from '~/components/data-table/data-table';
+import { SortDirection } from '~/components/data-table/data-column';
+import { createTree } from '~/models/tree';
import {
- StyleRulesCallback, WithStyles, withStyles, Card, CardContent, Grid, Table,
- TableHead, TableRow, TableCell, TableBody, Tooltip, IconButton
-} from '@material-ui/core';
-import { ArvadosTheme } from '~/common/custom-theme';
-import { MoreOptionsIcon } from '~/components/icon/icon';
-import { NodeResource } from '~/models/node';
-import { formatDate } from '~/common/formatters';
+ ResourceUuid, ResourceNodeInfo, ResourceNodeDomain, ResourceNodeHostname, ResourceNodeJobUuid,
+ ResourceNodeFirstPingAt, ResourceNodeLastPingAt, ResourceNodeIpAddress
+} from '~/views-components/data-explorer/renderers';
+import { ResourcesState } from '~/store/resources/resources';
-type CssRules = 'root' | 'tableRow';
+export enum ComputeNodePanelColumnNames {
+ INFO = 'Info',
+ UUID = 'UUID',
+ DOMAIN = 'Domain',
+ FIRST_PING_AT = 'First ping at',
+ HOSTNAME = 'Hostname',
+ IP_ADDRESS = 'IP Address',
+ JOB = 'Job',
+ LAST_PING_AT = 'Last ping at'
+}
-const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
- root: {
- width: '100%',
- overflow: 'auto'
+export const computeNodePanelColumns: DataColumns<string> = [
+ {
+ name: ComputeNodePanelColumnNames.INFO,
+ selected: true,
+ configurable: true,
+ filters: createTree(),
+ render: uuid => <ResourceNodeInfo uuid={uuid} />
+ },
+ {
+ name: ComputeNodePanelColumnNames.UUID,
+ selected: true,
+ configurable: true,
+ sortDirection: SortDirection.NONE,
+ filters: createTree(),
+ render: uuid => <ResourceUuid uuid={uuid} />
+ },
+ {
+ name: ComputeNodePanelColumnNames.DOMAIN,
+ selected: true,
+ configurable: true,
+ filters: createTree(),
+ render: uuid => <ResourceNodeDomain uuid={uuid} />
+ },
+ {
+ name: ComputeNodePanelColumnNames.FIRST_PING_AT,
+ selected: true,
+ configurable: true,
+ filters: createTree(),
+ render: uuid => <ResourceNodeFirstPingAt uuid={uuid} />
+ },
+ {
+ name: ComputeNodePanelColumnNames.HOSTNAME,
+ selected: true,
+ configurable: true,
+ filters: createTree(),
+ render: uuid => <ResourceNodeHostname uuid={uuid} />
+ },
+ {
+ name: ComputeNodePanelColumnNames.IP_ADDRESS,
+ selected: true,
+ configurable: true,
+ filters: createTree(),
+ render: uuid => <ResourceNodeIpAddress uuid={uuid} />
+ },
+ {
+ name: ComputeNodePanelColumnNames.JOB,
+ selected: true,
+ configurable: true,
+ filters: createTree(),
+ render: uuid => <ResourceNodeJobUuid uuid={uuid} />
},
- tableRow: {
- '& th': {
- whiteSpace: 'nowrap'
- }
+ {
+ name: ComputeNodePanelColumnNames.LAST_PING_AT,
+ selected: true,
+ configurable: true,
+ filters: createTree(),
+ render: uuid => <ResourceNodeLastPingAt uuid={uuid} />
}
-});
+];
export interface ComputeNodePanelRootActionProps {
- openRowOptions: (event: React.MouseEvent<HTMLElement>, computeNode: NodeResource) => void;
+ onItemClick: (item: string) => void;
+ onContextMenu: (event: React.MouseEvent<HTMLElement>, item: string) => void;
+ onItemDoubleClick: (item: string) => void;
}
export interface ComputeNodePanelRootDataProps {
- computeNodes: NodeResource[];
- hasComputeNodes: boolean;
+ resources: ResourcesState;
}
-type ComputeNodePanelRootProps = ComputeNodePanelRootActionProps & ComputeNodePanelRootDataProps & WithStyles<CssRules>;
+type ComputeNodePanelRootProps = ComputeNodePanelRootActionProps & ComputeNodePanelRootDataProps;
-export const ComputeNodePanelRoot = withStyles(styles)(
- ({ classes, hasComputeNodes, computeNodes, openRowOptions }: ComputeNodePanelRootProps) =>
- <Card className={classes.root}>
- <CardContent>
- {hasComputeNodes && <Grid container direction="row">
- <Grid item xs={12}>
- <Table>
- <TableHead>
- <TableRow className={classes.tableRow}>
- <TableCell>Info</TableCell>
- <TableCell>UUID</TableCell>
- <TableCell>Domain</TableCell>
- <TableCell>First ping at</TableCell>
- <TableCell>Hostname</TableCell>
- <TableCell>IP Address</TableCell>
- <TableCell>Job</TableCell>
- <TableCell>Last ping at</TableCell>
- <TableCell />
- </TableRow>
- </TableHead>
- <TableBody>
- {computeNodes.map((computeNode, index) =>
- <TableRow key={index} className={classes.tableRow}>
- <TableCell>{JSON.stringify(computeNode.info, null, 4)}</TableCell>
- <TableCell>{computeNode.uuid}</TableCell>
- <TableCell>{computeNode.domain}</TableCell>
- <TableCell>{formatDate(computeNode.firstPingAt) || '(none)'}</TableCell>
- <TableCell>{computeNode.hostname || '(none)'}</TableCell>
- <TableCell>{computeNode.ipAddress || '(none)'}</TableCell>
- <TableCell>{computeNode.jobUuid || '(none)'}</TableCell>
- <TableCell>{formatDate(computeNode.lastPingAt) || '(none)'}</TableCell>
- <TableCell>
- <Tooltip title="More options" disableFocusListener>
- <IconButton onClick={event => openRowOptions(event, computeNode)}>
- <MoreOptionsIcon />
- </IconButton>
- </Tooltip>
- </TableCell>
- </TableRow>)}
- </TableBody>
- </Table>
- </Grid>
- </Grid>}
- </CardContent>
- </Card>
-);
\ No newline at end of file
+export const ComputeNodePanelRoot = (props: ComputeNodePanelRootProps) => {
+ return <DataExplorer
+ id={COMPUTE_NODE_PANEL_ID}
+ onRowClick={props.onItemClick}
+ onRowDoubleClick={props.onItemDoubleClick}
+ onContextMenu={props.onContextMenu}
+ contextMenuColumn={true}
+ hideColumnSelector
+ hideSearchInput
+ dataTableDefaultView={
+ <DataTableDefaultView
+ icon={ShareMeIcon}
+ messages={['Your compute node list is empty.']} />
+ } />;
+};
\ No newline at end of file
diff --git a/src/views/compute-node-panel/compute-node-panel.tsx b/src/views/compute-node-panel/compute-node-panel.tsx
index a4f22c8..77a6abe 100644
--- a/src/views/compute-node-panel/compute-node-panel.tsx
+++ b/src/views/compute-node-panel/compute-node-panel.tsx
@@ -5,25 +5,25 @@
import { RootState } from '~/store/store';
import { Dispatch } from 'redux';
import { connect } from 'react-redux';
-import { } from '~/store/compute-nodes/compute-nodes-actions';
import {
ComputeNodePanelRoot,
ComputeNodePanelRootDataProps,
ComputeNodePanelRootActionProps
} from '~/views/compute-node-panel/compute-node-panel-root';
-import { openComputeNodeContextMenu } from '~/store/context-menu/context-menu-actions';
+import { openComputeNodeContextMenu, resourceKindToContextMenuKind } from '~/store/context-menu/context-menu-actions';
const mapStateToProps = (state: RootState): ComputeNodePanelRootDataProps => {
return {
- computeNodes: state.computeNodes,
- hasComputeNodes: state.computeNodes.length > 0
+ resources: state.resources
};
};
const mapDispatchToProps = (dispatch: Dispatch): ComputeNodePanelRootActionProps => ({
- openRowOptions: (event, computeNode) => {
- dispatch<any>(openComputeNodeContextMenu(event, computeNode));
- }
+ onContextMenu: (event, resourceUuid) => {
+ dispatch<any>(openComputeNodeContextMenu(event, resourceUuid));
+ },
+ onItemClick: (resourceUuid: string) => { return; },
+ onItemDoubleClick: uuid => { return; }
});
export const ComputeNodePanel = connect(mapStateToProps, mapDispatchToProps)(ComputeNodePanelRoot);
\ No newline at end of file
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list