21720:
[arvados.git] / services / workbench2 / src / views / collection-content-address-panel / collection-content-address-panel.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import React from 'react';
6 import { CustomStyleRulesCallback } from 'common/custom-theme';
7 import { Button } from '@mui/material';
8 import { WithStyles } from '@mui/styles';
9 import withStyles from '@mui/styles/withStyles';
10 import { CollectionIcon } from 'components/icon/icon';
11 import { ArvadosTheme } from 'common/custom-theme';
12 import { BackIcon } from 'components/icon/icon';
13 import { COLLECTIONS_CONTENT_ADDRESS_PANEL_ID } from 'store/collections-content-address-panel/collections-content-address-panel-actions';
14 import { DataExplorer } from "views-components/data-explorer/data-explorer";
15 import { Dispatch } from 'redux';
16 import {
17     resourceUuidToContextMenuKind,
18     openContextMenu
19 } from 'store/context-menu/context-menu-actions';
20 import { ResourceKind } from 'models/resource';
21 import { loadDetailsPanel } from 'store/details-panel/details-panel-action';
22 import { connect } from 'react-redux';
23 import { navigateTo } from 'store/navigation/navigation-action';
24 import { DataColumns } from 'components/data-table/data-table';
25 import { SortDirection } from 'components/data-table/data-column';
26 import { createTree } from 'models/tree';
27 import {
28     ResourceName,
29     ResourceOwnerName,
30     ResourceLastModifiedDate,
31     ResourceStatus
32 } from 'views-components/data-explorer/renderers';
33 import { getResource, ResourcesState } from 'store/resources/resources';
34 import { RootState } from 'store/store';
35 import { CollectionResource } from 'models/collection';
36
37 type CssRules = 'backLink' | 'backIcon' | 'root' | 'content';
38
39 const styles: CustomStyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
40     backLink: {
41         fontSize: '12px',
42         fontWeight: 600,
43         display: 'flex',
44         alignItems: 'center',
45         padding: theme.spacing(1),
46         marginBottom: theme.spacing(1),
47         color: theme.palette.grey["500"],
48     },
49     backIcon: {
50         marginRight: theme.spacing(1),
51     },
52     root: {
53         width: '100%',
54     },
55     content: {
56         // reserve space for the content address bar
57         height: `calc(100% - ${theme.spacing(7)})`,
58     },
59 });
60
61 enum CollectionContentAddressPanelColumnNames {
62     COLLECTION_WITH_THIS_ADDRESS = "Collection with this address",
63     STATUS = "Status",
64     LOCATION = "Location",
65     LAST_MODIFIED = "Last modified"
66 }
67
68 export const collectionContentAddressPanelColumns: DataColumns<string, CollectionResource> = [
69     {
70         name: CollectionContentAddressPanelColumnNames.COLLECTION_WITH_THIS_ADDRESS,
71         selected: true,
72         configurable: true,
73         sort: {direction: SortDirection.NONE, field: "uuid"},
74         filters: createTree(),
75         render: uuid => <ResourceName uuid={uuid} />
76     },
77     {
78         name: CollectionContentAddressPanelColumnNames.STATUS,
79         selected: true,
80         configurable: true,
81         filters: createTree(),
82         render: uuid => <ResourceStatus uuid={uuid} />
83     },
84     {
85         name: CollectionContentAddressPanelColumnNames.LOCATION,
86         selected: true,
87         configurable: true,
88         filters: createTree(),
89         render: uuid => <ResourceOwnerName uuid={uuid} />
90     },
91     {
92         name: CollectionContentAddressPanelColumnNames.LAST_MODIFIED,
93         selected: true,
94         configurable: true,
95         sort: {direction: SortDirection.DESC, field: "modifiedAt"},
96         filters: createTree(),
97         render: uuid => <ResourceLastModifiedDate uuid={uuid} />
98     }
99 ];
100
101 interface CollectionContentAddressPanelActionProps {
102     onContextMenu: (resources: ResourcesState) => (event: React.MouseEvent<any>, uuid: string) => void;
103     onItemClick: (item: string) => void;
104     onItemDoubleClick: (item: string) => void;
105 }
106
107 interface CollectionContentAddressPanelDataProps {
108     resources: ResourcesState;
109 }
110
111 const mapStateToProps = ({ resources }: RootState): CollectionContentAddressPanelDataProps => ({
112     resources
113 })
114
115 const mapDispatchToProps = (dispatch: Dispatch): CollectionContentAddressPanelActionProps => ({
116     onContextMenu: (resources: ResourcesState) => (event, resourceUuid) => {
117         const resource = getResource<CollectionResource>(resourceUuid)(resources);
118         const kind = dispatch<any>(resourceUuidToContextMenuKind(resourceUuid));
119         if (kind) {
120             dispatch<any>(openContextMenu(event, {
121                 name: resource ? resource.name : '',
122                 description: resource ? resource.description : '',
123                 storageClassesDesired: resource ? resource.storageClassesDesired : [],
124                 uuid: resourceUuid,
125                 ownerUuid: '',
126                 kind: ResourceKind.NONE,
127                 menuKind: kind
128             }));
129         }
130         dispatch<any>(loadDetailsPanel(resourceUuid));
131     },
132     onItemClick: (uuid: string) => {
133         dispatch<any>(loadDetailsPanel(uuid));
134     },
135     onItemDoubleClick: uuid => {
136         dispatch<any>(navigateTo(uuid));
137     }
138 });
139
140 interface CollectionContentAddressDataProps {
141     match: {
142         params: { id: string }
143     };
144 }
145
146 export const CollectionsContentAddressPanel = withStyles(styles)(
147     connect(mapStateToProps, mapDispatchToProps)(
148         class extends React.Component<CollectionContentAddressPanelActionProps & CollectionContentAddressPanelDataProps & CollectionContentAddressDataProps & WithStyles<CssRules>> {
149             render() {
150                 return <div className={this.props.classes.root}>
151                     <Button
152                         onClick={() => window.history.back()}
153                         className={this.props.classes.backLink}>
154                         <BackIcon className={this.props.classes.backIcon} />
155                         Back
156                     </Button>
157                     <div className={this.props.classes.content}><DataExplorer
158                         id={COLLECTIONS_CONTENT_ADDRESS_PANEL_ID}
159                         hideSearchInput
160                         onRowClick={this.props.onItemClick}
161                         onRowDoubleClick={this.props.onItemDoubleClick}
162                         onContextMenu={this.props.onContextMenu(this.props.resources)}
163                         contextMenuColumn={true}
164                         title={`Content address: ${this.props.match.params.id}`}
165                         defaultViewIcon={CollectionIcon}
166                         defaultViewMessages={['Collections with this content address not found.']} />
167                     </div>
168                 </div>;
169             }
170         }
171     )
172 );