import InsertDriveFile from '@material-ui/icons/InsertDriveFile';
import LastPage from '@material-ui/icons/LastPage';
import LibraryBooks from '@material-ui/icons/LibraryBooks';
+import ListAlt from '@material-ui/icons/ListAlt';
import Menu from '@material-ui/icons/Menu';
import MoreVert from '@material-ui/icons/MoreVert';
import Mail from '@material-ui/icons/Mail';
export const AddIcon: IconType = (props) => <Add {...props} />;
export const AddFavoriteIcon: IconType = (props) => <StarBorder {...props} />;
export const AdvancedIcon: IconType = (props) => <SettingsApplications {...props} />;
+export const AttributesIcon: IconType = (props) => <ListAlt {...props} />;
export const BackIcon: IconType = (props) => <ArrowBack {...props} />;
export const CustomizeTableIcon: IconType = (props) => <Menu {...props} />;
export const CommandIcon: IconType = (props) => <LastPage {...props} />;
import { Resource } from "~/models/resource";
-export interface RepositoriesResource extends Resource {
+export interface RepositoryResource extends Resource {
name: string;
cloneUrls: string[];
}
import { AxiosInstance } from "axios";
import { CommonResourceService } from "~/services/common-service/common-resource-service";
-import { RepositoriesResource } from '~/models/repositories';
+import { RepositoryResource } from '~/models/repositories';
import { ApiActions } from '~/services/api/api-actions';
- export class RepositoriesService extends CommonResourceService<RepositoriesResource> {
+ export class RepositoriesService extends CommonResourceService<RepositoryResource> {
constructor(serverApi: AxiosInstance, actions: ApiActions) {
super(serverApi, "repositories", actions);
}
import { ProjectResource } from '~/models/project';
import { ServiceRepository } from '~/services/services';
import { FilterBuilder } from '~/services/api/filter-builder';
-import { RepositoriesResource } from '~/models/repositories';
+import { RepositoryResource } from '~/models/repositories';
export const ADVANCED_TAB_DIALOG = 'advancedTabDialog';
return response;
};
-const repositoryApiResponse = (apiResponse: RepositoriesResource) => {
+const repositoryApiResponse = (apiResponse: RepositoryResource) => {
const { uuid, ownerUuid, createdAt, modifiedAt, modifiedByClientUuid, modifiedByUserUuid, name } = apiResponse;
const response = `"uuid": "${uuid}",
"owner_uuid": "${ownerUuid}",
import { isSidePanelTreeCategory } from '~/store/side-panel-tree/side-panel-tree-actions';
import { extractUuidKind, ResourceKind } from '~/models/resource';
import { Process } from '~/store/processes/process';
-import { RepositoriesResource } from '~/models/repositories';
+import { RepositoryResource } from '~/models/repositories';
export const contextMenuActions = unionize({
OPEN_CONTEXT_MENU: ofType<{ position: ContextMenuPosition, resource: ContextMenuResource }>(),
}));
};
-export const openRepositoryContextMenu = (event: React.MouseEvent<HTMLElement>, index: number, repository: RepositoriesResource) =>
+export const openRepositoryContextMenu = (event: React.MouseEvent<HTMLElement>, index: number, repository: RepositoryResource) =>
(dispatch: Dispatch, getState: () => RootState) => {
dispatch<any>(openContextMenu(event, {
name: '',
import { navigateToRepositories } from "~/store/navigation/navigation-action";
import { unionize, ofType, UnionOf } from "~/common/unionize";
import { dialogActions } from '~/store/dialog/dialog-actions';
+import { RepositoryResource } from "~/models/repositories";
export const repositoriesActions = unionize({
SET_REPOSITORIES: ofType<any>(),
export type RepositoriesActions = UnionOf<typeof repositoriesActions>;
export const REPOSITORIES_PANEL = 'repositoriesPanel';
-export const REPOSITORIES_SAMPLE_GIT_NAME = 'repositoriesSampleGit';
+export const REPOSITORIES_SAMPLE_GIT_DIALOG = 'repositoriesSampleGitDialog';
+export const REPOSITORY_ATTRIBUTES_DIALOG = 'repositoryAttributesDialog';
+export const REPOSITORY_CREATE_FORM_NAME = 'repositoryCreateFormName';
export const openRepositoriesSampleGitDialog = () =>
(dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
const uuidPrefix = getState().properties.uuidPrefix;
- dispatch(dialogActions.OPEN_DIALOG({ id: REPOSITORIES_SAMPLE_GIT_NAME, data: { uuidPrefix } }));
+ dispatch(dialogActions.OPEN_DIALOG({ id: REPOSITORIES_SAMPLE_GIT_DIALOG, data: { uuidPrefix } }));
+ };
+
+export const openRepositoryAttributes = (index: number) =>
+ (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ const repositoryData = getState().repositories.items[index];
+ dispatch(dialogActions.OPEN_DIALOG({ id: REPOSITORY_ATTRIBUTES_DIALOG, data: { repositoryData } }));
+ };
+
+export const openRepositoryCreateDialog = () =>
+ async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ dispatch(dialogActions.OPEN_DIALOG({ id: REPOSITORY_CREATE_FORM_NAME, data: {} }));
+ };
+
+export const createRepository = (repository: RepositoryResource) =>
+ async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ const userUuid = await services.authService.getUuid();
+ const user = await services.userService.get(userUuid!);
+ await services.repositoriesService.create({ name: `${user.username}/${repository.name}` });
};
const repositoriesBindedActions = bindDataExplorerActions(REPOSITORIES_PANEL);
// SPDX-License-Identifier: AGPL-3.0
import { repositoriesActions, RepositoriesActions } from '~/store/repositories/repositories-actions';
-import { RepositoriesResource } from '~/models/repositories';
+import { RepositoryResource } from '~/models/repositories';
interface Repositories {
- items: RepositoriesResource[];
+ items: RepositoryResource[];
}
const initialState: Repositories = {
export const MOVE_TO_VALIDATION = [require];
-export const PROCESS_NAME_VALIDATION = [require, maxLength(255)];
\ No newline at end of file
+export const PROCESS_NAME_VALIDATION = [require, maxLength(255)];
+
+export const REPOSITORY_NAME_VALIDATION = [require, maxLength(255)];
\ No newline at end of file
// SPDX-License-Identifier: AGPL-3.0
import { ContextMenuActionSet } from "~/views-components/context-menu/context-menu-action-set";
-import { AdvancedIcon, RemoveIcon, ShareIcon } from "~/components/icon/icon";
+import { AdvancedIcon, RemoveIcon, ShareIcon, AttributesIcon } from "~/components/icon/icon";
import { openFileRemoveDialog, openRenameFileDialog } from '~/store/collection-panel/collection-panel-files/collection-panel-files-actions';
import { openAdvancedTabDialog } from "~/store/advanced-tab/advanced-tab";
+import { openRepositoryAttributes } from "~/store/repositories/repositories-actions";
export const repositoryActionSet: ContextMenuActionSet = [[{
name: "Attributes",
- icon: AdvancedIcon,
+ icon: AttributesIcon,
execute: (dispatch, resource) => {
- dispatch<any>(openRenameFileDialog({ name: resource.name, id: resource.uuid }));
+ dispatch<any>(openRepositoryAttributes(resource.index!));
}
}, {
name: "Share",
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import { InjectedFormProps } from 'redux-form';
+import { WithDialogProps } from '~/store/dialog/with-dialog';
+import { FormDialog } from '~/components/form-dialog/form-dialog';
+import { RepositoryNameField } from '~/views-components/form-fields/repository-form-fields';
+
+type DialogRepositoryProps = WithDialogProps<{}> & InjectedFormProps<any>;
+
+export const DialogRepositoryCreate = (props: DialogRepositoryProps) =>
+ <FormDialog
+ dialogTitle='Add new repository'
+ formFields={RepositoryAddField}
+ submitLabel='CREATE REPOSITORY'
+ {...props}
+ />;
+
+const RepositoryAddField = () =>
+ <RepositoryNameField />;
+
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { compose } from "redux";
+import { reduxForm } from 'redux-form';
+import { withDialog } from "~/store/dialog/with-dialog";
+import { createRepository, REPOSITORY_CREATE_FORM_NAME } from "~/store/repositories/repositories-actions";
+import { DialogRepositoryCreate } from "~/views-components/dialog-create/dialog-repository-create";
+
+export const CreateRepositoryDialog = compose(
+ withDialog(REPOSITORY_CREATE_FORM_NAME),
+ reduxForm<any>({
+ form: REPOSITORY_CREATE_FORM_NAME,
+ onSubmit: (repositoryName, dispatch) => {
+ dispatch(createRepository(repositoryName));
+ }
+ })
+)(DialogRepositoryCreate);
\ No newline at end of file
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from "react";
+import { Field } from "redux-form";
+import { TextField } from "~/components/text-field/text-field";
+import { REPOSITORY_NAME_VALIDATION } from "~/validators/validators";
+
+export const RepositoryNameField = () =>
+ <span>
+ pawelkowalczyk/
+ <Field
+ name='name'
+ component={TextField}
+ validate={REPOSITORY_NAME_VALIDATION}
+ label="Name"
+ autoFocus={true} />.git<br/>
+ It may take a minute or two before you can clone your new repository.
+ </span>;
\ No newline at end of file
import { Dialog, DialogTitle, DialogContent, DialogActions, Button, Typography } from "@material-ui/core";
import { WithDialogProps } from "~/store/dialog/with-dialog";
import { withDialog } from '~/store/dialog/with-dialog';
-import { REPOSITORIES_SAMPLE_GIT_NAME } from "~/store/repositories/repositories-actions";
+import { REPOSITORIES_SAMPLE_GIT_DIALOG } from "~/store/repositories/repositories-actions";
import { DefaultCodeSnippet } from '~/components/default-code-snippet/default-code-snippet';
import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core/styles';
import { ArvadosTheme } from '~/common/custom-theme';
type RepositoriesSampleGitProps = RepositoriesSampleGitDataProps & WithStyles<CssRules>;
export const RepositoriesSampleGitDialog = compose(
- withDialog(REPOSITORIES_SAMPLE_GIT_NAME),
+ withDialog(REPOSITORIES_SAMPLE_GIT_DIALOG),
withStyles(styles))(
(props: WithDialogProps<RepositoriesSampleGitProps> & RepositoriesSampleGitProps) =>
<Dialog open={props.open}
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from "react";
+import { Dialog, DialogTitle, DialogContent, DialogActions, Button, Typography, Grid } from "@material-ui/core";
+import { WithDialogProps } from "~/store/dialog/with-dialog";
+import { withDialog } from '~/store/dialog/with-dialog';
+import { REPOSITORY_ATTRIBUTES_DIALOG } from "~/store/repositories/repositories-actions";
+import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core/styles';
+import { ArvadosTheme } from '~/common/custom-theme';
+import { compose } from "redux";
+import { RepositoryResource } from "~/models/repositories";
+
+type CssRules = 'rightContainer' | 'leftContainer' | 'spacing';
+
+const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+ rightContainer: {
+ textAlign: 'right',
+ paddingRight: theme.spacing.unit * 2,
+ color: theme.palette.grey["500"]
+ },
+ leftContainer: {
+ textAlign: 'left',
+ paddingLeft: theme.spacing.unit * 2
+ },
+ spacing: {
+ paddingTop: theme.spacing.unit * 2
+ },
+});
+
+interface RepositoryAttributesDataProps {
+ repositoryData: RepositoryResource;
+}
+
+type RepositoryAttributesProps = RepositoryAttributesDataProps & WithStyles<CssRules>;
+
+export const RepositoryAttributesDialog = compose(
+ withDialog(REPOSITORY_ATTRIBUTES_DIALOG),
+ withStyles(styles))(
+ (props: WithDialogProps<RepositoryAttributesProps> & RepositoryAttributesProps) =>
+ <Dialog open={props.open}
+ onClose={props.closeDialog}
+ fullWidth
+ maxWidth="sm">
+ <DialogTitle>Attributes</DialogTitle>
+ <DialogContent>
+ <Typography variant="body2" className={props.classes.spacing}>
+ {props.data.repositoryData && attributes(props.data.repositoryData, props.classes)}
+ </Typography>
+ </DialogContent>
+ <DialogActions>
+ <Button
+ variant='flat'
+ color='primary'
+ onClick={props.closeDialog}>
+ Close
+ </Button>
+ </DialogActions>
+ </Dialog>
+ );
+
+const attributes = (repositoryData: RepositoryResource, classes: any) => {
+ const { uuid, ownerUuid, createdAt, modifiedAt, modifiedByClientUuid, modifiedByUserUuid, name } = repositoryData;
+ return (
+ <span>
+ <Grid container direction="row">
+ <Grid item xs={5} className={classes.rightContainer}>
+ <Grid item>Name</Grid>
+ <Grid item>Owner uuid</Grid>
+ <Grid item>Created at</Grid>
+ <Grid item>Modified at</Grid>
+ <Grid item>Modified by user uuid</Grid>
+ <Grid item>Modified by client uuid</Grid>
+ <Grid item>uuid</Grid>
+ </Grid>
+ <Grid item xs={7} className={classes.leftContainer}>
+ <Grid item>{name}</Grid>
+ <Grid item>{ownerUuid}</Grid>
+ <Grid item>{createdAt}</Grid>
+ <Grid item>{modifiedAt}</Grid>
+ <Grid item>{modifiedByUserUuid}</Grid>
+ <Grid item>{modifiedByClientUuid}</Grid>
+ <Grid item>{uuid}</Grid>
+ </Grid>
+ </Grid>
+ </span>
+ );
+};
import { Dispatch, compose } from 'redux';
import { RootState } from '~/store/store';
import { HelpIcon, AddIcon, MoreOptionsIcon } from '~/components/icon/icon';
-import { loadRepositoriesData, openRepositoriesSampleGitDialog } from '~/store/repositories/repositories-actions';
-import { RepositoriesResource } from '~/models/repositories';
+import { loadRepositoriesData, openRepositoriesSampleGitDialog, openRepositoryCreateDialog } from '~/store/repositories/repositories-actions';
+import { RepositoryResource } from '~/models/repositories';
import { openRepositoryContextMenu } from '~/store/context-menu/context-menu-actions';
};
};
-const mapDispatchToProps = (dispatch: Dispatch): Pick<RepositoriesActionProps, 'onOptionsMenuOpen' | 'loadRepositories' | 'openRepositoriesSampleGitDialog'> => ({
+const mapDispatchToProps = (dispatch: Dispatch): Pick<RepositoriesActionProps, 'onOptionsMenuOpen' | 'loadRepositories' | 'openRepositoriesSampleGitDialog' | 'openRepositoryCreateDialog'> => ({
loadRepositories: () => dispatch<any>(loadRepositoriesData()),
onOptionsMenuOpen: (event, index, repository) => {
dispatch<any>(openRepositoryContextMenu(event, index, repository));
},
- openRepositoriesSampleGitDialog: () => dispatch<any>(openRepositoriesSampleGitDialog())
+ openRepositoriesSampleGitDialog: () => dispatch<any>(openRepositoriesSampleGitDialog()),
+ openRepositoryCreateDialog: () => dispatch<any>(openRepositoryCreateDialog())
});
interface RepositoriesActionProps {
loadRepositories: () => void;
- onOptionsMenuOpen: (event: React.MouseEvent<HTMLElement>, index: number, repository: RepositoriesResource) => void;
+ onOptionsMenuOpen: (event: React.MouseEvent<HTMLElement>, index: number, repository: RepositoryResource) => void;
openRepositoriesSampleGitDialog: () => void;
+ openRepositoryCreateDialog: () => void;
}
interface RepositoriesDataProps {
- repositories: RepositoriesResource[];
+ repositories: RepositoryResource[];
}
this.props.loadRepositories();
}
render() {
- const { classes, repositories, onOptionsMenuOpen, openRepositoriesSampleGitDialog } = this.props;
- console.log(repositories);
+ const { classes, repositories, onOptionsMenuOpen, openRepositoriesSampleGitDialog, openRepositoryCreateDialog } = this.props;
return (
<Card>
<CardContent>
</Typography>
</Grid>
<Grid item xs={4} className={classes.button}>
- <Button variant="contained" color="primary">
+ <Button variant="contained" color="primary" onClick={openRepositoryCreateDialog}>
<AddIcon /> NEW REPOSITORY
</Button>
</Grid>
import { ProjectPropertiesDialog } from '~/views-components/project-properties-dialog/project-properties-dialog';
import { RepositoriesPanel } from '~/views/repositories-panel/repositories-panel';
import { RepositoriesSampleGitDialog } from '~/views-components/repositories-sample-git-dialog/repositories-sample-git-dialog';
+import { RepositoryAttributesDialog } from '~/views-components/repository-attributes-dialog/repository-attributes-dialog';
+import { CreateRepositoryDialog } from '~/views-components/dialog-forms/create-repository-dialog';
type CssRules = 'root' | 'container' | 'splitter' | 'asidePanel' | 'contentWrapper' | 'content';
<CopyProcessDialog />
<CreateCollectionDialog />
<CreateProjectDialog />
+ <CreateRepositoryDialog />
<CurrentTokenDialog />
<FileRemoveDialog />
<FilesUploadCollectionDialog />
<ProjectPropertiesDialog />
<RemoveProcessDialog />
<RenameFileDialog />
+ <RepositoryAttributesDialog />
<RepositoriesSampleGitDialog />
<RichTextEditorDialog />
<SharingDialog />