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