"scripts": {
"start": "react-scripts-ts start",
"build": "REACT_APP_BUILD_NUMBER=$BUILD_NUMBER REACT_APP_GIT_COMMIT=$GIT_COMMIT react-scripts-ts build",
- "test": "react-scripts-ts test --env=jsdom",
+ "test": "CI=true react-scripts-ts test --env=jsdom",
"eject": "react-scripts-ts eject",
"lint": "tslint src/** -t verbose"
},
import { getBuildInfo } from '~/common/app-info';
import { DragDropContextProvider } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
+import { initAdvanceFormProjectsTree } from '~/store/search-bar/search-bar-actions';
console.log(`Starting arvados [${getBuildInfo()}]`);
initWebSocket(config, services.authService, store);
await store.dispatch(loadWorkbench());
addRouteChangeHandlers(history, store);
+ // ToDo: move to searchBar component
+ store.dispatch(initAdvanceFormProjectsTree());
}
};
};
import { ResourceKind } from '~/models/resource';
-export interface SearchBarAdvanceFormData {
+export type SearchBarAdvanceFormData = {
type?: ResourceKind;
cluster?: ClusterObjectType;
- project?: string;
+ projectUuid?: string;
inTrash: boolean;
dateFrom: string;
dateTo: string;
saveQuery: boolean;
searchQuery: string;
+ properties: PropertyValues[];
+} & PropertyValues;
+
+export interface PropertyValues {
+ key: string;
+ value: string;
}
export enum ClusterObjectType {
import { unionize, ofType, UnionOf } from "~/common/unionize";
import { GroupContentsResource, GroupContentsResourcePrefix } from '~/services/groups-service/groups-service';
import { Dispatch } from 'redux';
+import { change, arrayPush } from 'redux-form';
import { RootState } from '~/store/store';
+import { initUserProject } from '~/store/tree-picker/tree-picker-actions';
import { ServiceRepository } from '~/services/services';
import { FilterBuilder } from "~/services/api/filter-builder";
import { ResourceKind } from '~/models/resource';
import { SearchView } from '~/store/search-bar/search-bar-reducer';
import { navigateToSearchResults, navigateTo } from '~/store/navigation/navigation-action';
import { snackbarActions, SnackbarKind } from '~/store/snackbar/snackbar-actions';
-import { SearchBarAdvanceFormData } from '~/models/search-bar';
import { initialize } from 'redux-form';
+import { SearchBarAdvanceFormData, PropertyValues } from '~/models/search-bar';
export const searchBarActions = unionize({
SET_CURRENT_VIEW: ofType<string>(),
export const SEARCH_BAR_ADVANCE_FORM_NAME = 'searchBarAdvanceFormName';
+export const SEARCH_BAR_ADVANCE_FORM_PICKER_ID = 'searchBarAdvanceFormPickerId';
+
export const goToView = (currentView: string) => searchBarActions.SET_CURRENT_VIEW(currentView);
export const saveRecentQuery = (query: string) =>
.addEqual('groupClass', GroupClass.PROJECT, GroupContentsResourcePrefix.PROJECT)
.getFilters();
};
+
+export const initAdvanceFormProjectsTree = () =>
+ (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ dispatch<any>(initUserProject(SEARCH_BAR_ADVANCE_FORM_PICKER_ID));
+ };
+
+export const changeAdvanceFormProperty = (property: string, value: PropertyValues[] | string = '') =>
+ (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ dispatch(change(SEARCH_BAR_ADVANCE_FORM_NAME, property, value));
+ };
+
+export const updateAdvanceFormProperties = (propertyValues: PropertyValues) =>
+ (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ dispatch(arrayPush(SEARCH_BAR_ADVANCE_FORM_NAME, 'properties', propertyValues));
+ };
\ No newline at end of file
// SPDX-License-Identifier: AGPL-3.0
import * as React from "react";
-import { Field } from 'redux-form';
+import { Field, WrappedFieldProps } from 'redux-form';
import { TextField, DateTextField } from "~/components/text-field/text-field";
import { CheckboxField } from '~/components/checkbox-field/checkbox-field';
import { NativeSelectField } from '~/components/select-field/select-field';
import { ResourceKind } from '~/models/resource';
import { ClusterObjectType } from '~/models/search-bar';
+import { HomeTreePicker } from '~/views-components/projects-tree-picker/home-tree-picker';
+import { SEARCH_BAR_ADVANCE_FORM_PICKER_ID } from '~/store/search-bar/search-bar-actions';
export const SearchBarTypeField = () =>
<Field
]} />;
export const SearchBarProjectField = () =>
- <div>Box</div>;
+ <Field
+ name='projectUuid'
+ component={ProjectsPicker} />;
+
+const ProjectsPicker = (props: WrappedFieldProps) =>
+ <div style={{ height: '100px', display: 'flex', flexDirection: 'column', overflow: 'overlay' }}>
+ <HomeTreePicker pickerId={SEARCH_BAR_ADVANCE_FORM_PICKER_ID} />
+ </div>;
export const SearchBarTrashField = () =>
<Field
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import { Dispatch } from 'redux';
+import { connect } from 'react-redux';
+import { InjectedFormProps, formValueSelector } from 'redux-form';
+import { Grid, withStyles, StyleRulesCallback, WithStyles, Button } from '@material-ui/core';
+import { RootState } from '~/store/store';
+import {
+ SEARCH_BAR_ADVANCE_FORM_NAME,
+ changeAdvanceFormProperty,
+ updateAdvanceFormProperties
+} from '~/store/search-bar/search-bar-actions';
+import { PropertyValues } from '~/models/search-bar';
+import { ArvadosTheme } from '~/common/custom-theme';
+import { SearchBarKeyField, SearchBarValueField } from '~/views-components/form-fields/search-bar-form-fields';
+import { Chips } from '~/components/chips/chips';
+
+type CssRules = 'label' | 'button';
+
+const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+ label: {
+ color: theme.palette.grey["500"],
+ fontSize: '0.8125rem',
+ alignSelf: 'center'
+ },
+ button: {
+ boxShadow: 'none'
+ }
+});
+
+interface SearchBarAdvancedPropertiesViewDataProps {
+ submitting: boolean;
+ invalid: boolean;
+ pristine: boolean;
+ propertyValues: PropertyValues;
+ fields: PropertyValues[];
+}
+
+interface SearchBarAdvancedPropertiesViewActionProps {
+ setProps: () => void;
+ addProp: (propertyValues: PropertyValues) => void;
+ getAllFields: (propertyValues: PropertyValues[]) => PropertyValues[] | [];
+}
+
+type SearchBarAdvancedPropertiesViewProps = SearchBarAdvancedPropertiesViewDataProps
+ & SearchBarAdvancedPropertiesViewActionProps
+ & InjectedFormProps & WithStyles<CssRules>;
+
+const selector = formValueSelector(SEARCH_BAR_ADVANCE_FORM_NAME);
+const mapStateToProps = (state: RootState) => {
+ return {
+ propertyValues: selector(state, 'key', 'value')
+ };
+};
+
+const mapDispatchToProps = (dispatch: Dispatch) => ({
+ setProps: (propertyValues: PropertyValues[]) => {
+ dispatch<any>(changeAdvanceFormProperty('properties', propertyValues));
+ },
+ addProp: (propertyValues: PropertyValues) => {
+ dispatch<any>(updateAdvanceFormProperties(propertyValues));
+ dispatch<any>(changeAdvanceFormProperty('key'));
+ dispatch<any>(changeAdvanceFormProperty('value'));
+ },
+ getAllFields: (fields: any) => {
+ return fields.getAll() || [];
+ }
+});
+
+export const SearchBarAdvancedPropertiesView = connect(mapStateToProps, mapDispatchToProps)(
+ withStyles(styles)(
+ ({ classes, fields, propertyValues, setProps, addProp, getAllFields }: SearchBarAdvancedPropertiesViewProps) =>
+ <Grid container item xs={12} spacing={16}>
+ <Grid item xs={2} className={classes.label}>Properties</Grid>
+ <Grid item xs={4}>
+ <SearchBarKeyField />
+ </Grid>
+ <Grid item xs={4}>
+ <SearchBarValueField />
+ </Grid>
+ <Grid container item xs={2} justify='flex-end' alignItems="center">
+ <Button className={classes.button} onClick={() => addProp(propertyValues)}
+ color="primary"
+ size='small'
+ variant="contained">
+ Add
+ </Button>
+ </Grid>
+ <Grid item xs={2} />
+ <Grid container item xs={10} spacing={8}>
+ <Chips values={getAllFields(fields)}
+ deletable
+ onChange={setProps}
+ getLabel={(field: PropertyValues) => `${field.key}: ${field.value}`} />
+ </Grid>
+ </Grid>
+ )
+);
\ No newline at end of file
// SPDX-License-Identifier: AGPL-3.0
import * as React from 'react';
-import { reduxForm, reset, InjectedFormProps } from 'redux-form';
+import { reduxForm, reset, InjectedFormProps, FieldArray } from 'redux-form';
import { compose, Dispatch } from 'redux';
import { Paper, StyleRulesCallback, withStyles, WithStyles, Button, Grid, IconButton, CircularProgress } from '@material-ui/core';
import { SearchView } from '~/store/search-bar/search-bar-reducer';
import { ArvadosTheme } from '~/common/custom-theme';
import { CloseIcon } from '~/components/icon/icon';
import { SearchBarAdvanceFormData } from '~/models/search-bar';
+import { SearchBarAdvancedPropertiesView } from './search-bar-advanced-properties-view';
import {
SearchBarTypeField, SearchBarClusterField, SearchBarProjectField, SearchBarTrashField,
- SearchBarDataFromField, SearchBarDataToField, SearchBarKeyField, SearchBarValueField,
+ SearchBarDataFromField, SearchBarDataToField,
SearchBarSaveSearchField, SearchBarQuerySearchField
} from '~/views-components/form-fields/search-bar-form-fields';
}
}),
withStyles(styles))(
- ({ classes, setView, handleSubmit, invalid, submitting, pristine }: SearchBarAdvancedViewProps) =>
+ ({ classes, setView, handleSubmit, submitting }: SearchBarAdvancedViewProps) =>
<Paper className={classes.searchView}>
<form onSubmit={handleSubmit}>
<Grid container direction="column" justify="flex-start" alignItems="flex-start">
</Grid>
</Grid>
<Grid container item xs={12} className={classes.container}>
- <Grid container item xs={12} spacing={16}>
- <Grid item xs={2} className={classes.label}>Properties</Grid>
- <Grid item xs={4}>
- <SearchBarKeyField />
- </Grid>
- <Grid item xs={4}>
- <SearchBarValueField />
- </Grid>
- <Grid container item xs={2} justify='flex-end' alignItems="center">
- <Button className={classes.button}
- color="primary"
- size='small'
- variant="contained">
- Add
- </Button>
- </Grid>
- </Grid>
+ <FieldArray name="properties" component={SearchBarAdvancedPropertiesView} />
<Grid container item xs={12} justify="flex-start" alignItems="center" spacing={16}>
<Grid item xs={2} className={classes.label} />
<Grid item xs={4}>