Merge branch 'master' into 14452-my-account
[arvados-workbench2.git] / src / views / repositories-panel / repositories-panel.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import * as React from 'react';
6 import { connect } from 'react-redux';
7 import { Grid, Typography, Button, Card, CardContent, TableBody, TableCell, TableHead, TableRow, Table, Tooltip, IconButton } from '@material-ui/core';
8 import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core/styles';
9 import { ArvadosTheme } from '~/common/custom-theme';
10 import { Link } from 'react-router-dom';
11 import { Dispatch, compose } from 'redux';
12 import { RootState } from '~/store/store';
13 import { HelpIcon, AddIcon, MoreOptionsIcon } from '~/components/icon/icon';
14 import { loadRepositoriesData, openRepositoriesSampleGitDialog, openRepositoryCreateDialog } from '~/store/repositories/repositories-actions';
15 import { RepositoryResource } from '~/models/repositories';
16 import { openRepositoryContextMenu } from '~/store/context-menu/context-menu-actions';
17 import { Routes } from '~/routes/routes';
18
19
20 type CssRules = 'link' | 'button' | 'icon' | 'iconRow' | 'moreOptionsButton' | 'moreOptions' | 'cloneUrls';
21
22 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
23     link: {
24         textDecoration: 'none',
25         color: theme.palette.primary.main,
26         "&:hover": {
27             color: theme.palette.primary.dark,
28             transition: 'all 0.5s ease'
29         }
30     },
31     button: {
32         textAlign: 'right',
33         alignSelf: 'center'
34     },
35     icon: {
36         cursor: 'pointer',
37         color: theme.palette.grey["500"],
38         "&:hover": {
39             color: theme.palette.common.black,
40             transition: 'all 0.5s ease'
41         }
42     },
43     iconRow: {
44         paddingTop: theme.spacing.unit * 2,
45         textAlign: 'right'
46     },
47     moreOptionsButton: {
48         padding: 0
49     },
50     moreOptions: {
51         textAlign: 'right',
52         '&:last-child': {
53             paddingRight: 0
54         }
55     },
56     cloneUrls: {
57         whiteSpace: 'pre-wrap'
58     }
59 });
60
61 const mapStateToProps = (state: RootState) => {
62     return {
63         repositories: state.repositories.items
64     };
65 };
66
67 const mapDispatchToProps = (dispatch: Dispatch): Pick<RepositoriesActionProps, 'onOptionsMenuOpen' | 'loadRepositories' | 'openRepositoriesSampleGitDialog' | 'openRepositoryCreateDialog'> => ({
68     loadRepositories: () => dispatch<any>(loadRepositoriesData()),
69     onOptionsMenuOpen: (event, repository) => {
70         dispatch<any>(openRepositoryContextMenu(event, repository));
71     },
72     openRepositoriesSampleGitDialog: () => dispatch<any>(openRepositoriesSampleGitDialog()),
73     openRepositoryCreateDialog: () => dispatch<any>(openRepositoryCreateDialog())
74 });
75
76 interface RepositoriesActionProps {
77     loadRepositories: () => void;
78     onOptionsMenuOpen: (event: React.MouseEvent<HTMLElement>, repository: RepositoryResource) => void;
79     openRepositoriesSampleGitDialog: () => void;
80     openRepositoryCreateDialog: () => void;
81 }
82
83 interface RepositoriesDataProps {
84     repositories: RepositoryResource[];
85 }
86
87
88 type RepositoriesProps = RepositoriesDataProps & RepositoriesActionProps & WithStyles<CssRules>;
89
90 export const RepositoriesPanel = compose(
91     withStyles(styles),
92     connect(mapStateToProps, mapDispatchToProps))(
93         class extends React.Component<RepositoriesProps> {
94             componentDidMount() {
95                 this.props.loadRepositories();
96             }
97             render() {
98                 const { classes, repositories, onOptionsMenuOpen, openRepositoriesSampleGitDialog, openRepositoryCreateDialog } = this.props;
99                 return (
100                     <Card>
101                         <CardContent>
102                             <Grid container direction="row">
103                                 <Grid item xs={8}>
104                                     <Typography variant="body2">
105                                         When you are using an Arvados virtual machine, you should clone the https:// URLs. This will authenticate automatically using your API token. <br />
106                                         In order to clone git repositories using SSH, <Link to={Routes.SSH_KEYS} className={classes.link}>add an SSH key to your account</Link> and clone the git@ URLs.
107                                     </Typography>
108                                 </Grid>
109                                 <Grid item xs={4} className={classes.button}>
110                                     <Button variant="contained" color="primary" onClick={openRepositoryCreateDialog}>
111                                         <AddIcon /> NEW REPOSITORY
112                                     </Button>
113                                 </Grid>
114                             </Grid>
115                             <Grid item xs={12}>
116                                 <div className={classes.iconRow}>
117                                     <Tooltip title="Sample git quick start">
118                                         <IconButton className={classes.moreOptionsButton} onClick={openRepositoriesSampleGitDialog}>
119                                             <HelpIcon className={classes.icon} />
120                                         </IconButton>
121                                     </Tooltip>
122                                 </div>
123                             </Grid>
124                             <Grid item xs={12}>
125                                 {repositories && <Table>
126                                     <TableHead>
127                                         <TableRow>
128                                             <TableCell>Name</TableCell>
129                                             <TableCell>URL</TableCell>
130                                             <TableCell />
131                                         </TableRow>
132                                     </TableHead>
133                                     <TableBody>
134                                         {repositories.map((repository, index) =>
135                                             <TableRow key={index}>
136                                                 <TableCell>{repository.name}</TableCell>
137                                                 <TableCell className={classes.cloneUrls}>{repository.cloneUrls.join("\n")}</TableCell>
138                                                 <TableCell className={classes.moreOptions}>
139                                                     <Tooltip title="More options" disableFocusListener>
140                                                         <IconButton onClick={event => onOptionsMenuOpen(event, repository)} className={classes.moreOptionsButton}>
141                                                             <MoreOptionsIcon />
142                                                         </IconButton>
143                                                     </Tooltip>
144                                                 </TableCell>
145                                             </TableRow>)}
146                                     </TableBody>
147                                 </Table>}
148                             </Grid>
149                         </CardContent>
150                     </Card>
151                 );
152             }
153         }
154     );