16718: Merge branch 'master' into 16718-past-collection-versions-search
authorLucas Di Pentima <lucas@di-pentima.com.ar>
Mon, 12 Oct 2020 22:14:34 +0000 (19:14 -0300)
committerLucas Di Pentima <lucas@di-pentima.com.ar>
Mon, 12 Oct 2020 22:14:34 +0000 (19:14 -0300)
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas@di-pentima.com.ar>

src/components/data-table/data-table.tsx
src/models/search-bar.ts
src/store/search-bar/search-bar-actions.test.ts
src/store/search-bar/search-bar-actions.ts
src/store/search-bar/search-query/arv-parser.ts
src/store/search-results-panel/search-results-middleware-service.ts
src/views-components/data-explorer/renderers.tsx
src/views-components/form-fields/search-bar-form-fields.tsx
src/views-components/search-bar/search-bar-advanced-view.tsx
src/views/search-results-panel/search-results-panel-view.tsx

index 4e2b430ab74f1249b4af0b84ebff0f3cdf4aedb8..87386d50920a329fd9350311640a656e83e14217 100644 (file)
@@ -55,7 +55,8 @@ const styles: StyleRulesCallback<CssRules> = (theme: Theme) => ({
         padding: theme.spacing.unit
     },
     tableCell: {
-        wordWrap: 'break-word'
+        wordWrap: 'break-word',
+        paddingRight: '24px'
     },
     tableCellWorkflows: {
         '&:nth-last-child(2)': {
@@ -107,8 +108,8 @@ export const DataTable = withStyles(styles)(
 
         renderHeadCell = (column: DataColumn<T>, index: number) => {
             const { name, key, renderHeader, filters, sortDirection } = column;
-            const { onSortToggle, onFiltersChange } = this.props;
-            return <TableCell key={key || index}>
+            const { onSortToggle, onFiltersChange, classes } = this.props;
+            return <TableCell className={classes.tableCell} key={key || index}>
                 {renderHeader ?
                     renderHeader() :
                     countNodes(filters) > 0
index c71faf2ff47c132453e923a8d021816865ef67ee..09b8b6b70d02670f115ab58f218c06253c630652 100644 (file)
@@ -9,6 +9,7 @@ export type SearchBarAdvancedFormData = {
     cluster?: string;
     projectUuid?: string;
     inTrash: boolean;
+    pastVersions: boolean;
     dateFrom: string;
     dateTo: string;
     saveQuery: boolean;
index 68804dfb6393e885de4bf91b0f3041a4ff46fac2..194ca2d71765786807859dc0dbb549012ddcb57a 100644 (file)
@@ -8,13 +8,14 @@ import { ResourceKind } from "~/models/resource";
 describe('search-bar-actions', () => {
     describe('getAdvancedDataFromQuery', () => {
         it('should correctly build advanced data record from query #1', () => {
-            const r = getAdvancedDataFromQuery('val0 has:"file size":"100mb" val2 has:"user":"daniel" is:starred val2 val0 is:trashed');
+            const r = getAdvancedDataFromQuery('val0 has:"file size":"100mb" val2 has:"user":"daniel" is:starred val2 val0');
             expect(r).toEqual({
                 searchValue: 'val0 val2',
                 type: undefined,
                 cluster: undefined,
                 projectUuid: undefined,
-                inTrash: true,
+                inTrash: false,
+                pastVersions: false,
                 dateFrom: '',
                 dateTo: '',
                 properties: [{
@@ -30,13 +31,14 @@ describe('search-bar-actions', () => {
         });
 
         it('should correctly build advanced data record from query #2', () => {
-            const r = getAdvancedDataFromQuery('document from:2017-08-01 pdf has:"filesize":"101mb" is:trashed type:arvados#collection cluster:c97qx');
+            const r = getAdvancedDataFromQuery('document from:2017-08-01 pdf has:"filesize":"101mb" is:trashed type:arvados#collection cluster:c97qx is:pastVersion');
             expect(r).toEqual({
                 searchValue: 'document pdf',
                 type: ResourceKind.COLLECTION,
                 cluster: 'c97qx',
                 projectUuid: undefined,
                 inTrash: true,
+                pastVersions: true,
                 dateFrom: '2017-08-01',
                 dateTo: '',
                 properties: [{
@@ -57,6 +59,7 @@ describe('search-bar-actions', () => {
                 cluster: 'c97qx',
                 projectUuid: undefined,
                 inTrash: true,
+                pastVersions: false,
                 dateFrom: '2017-08-01',
                 dateTo: '',
                 properties: [
@@ -70,6 +73,27 @@ describe('search-bar-actions', () => {
             expect(q).toBe('document pdf type:arvados#collection cluster:c97qx is:trashed from:2017-08-01 has:"file size":"101mb" has:"Species":"Human" has:"Species":"Canine"');
         });
 
+        it('should build query from advanced data #2', () => {
+            const q = getQueryFromAdvancedData({
+                searchValue: 'document pdf',
+                type: ResourceKind.COLLECTION,
+                cluster: 'c97qx',
+                projectUuid: undefined,
+                inTrash: false,
+                pastVersions: true,
+                dateFrom: '2017-08-01',
+                dateTo: '',
+                properties: [
+                    { key: 'file size', value: '101mb' },
+                    { key: 'Species', value: 'Human' },
+                    { key: 'Species', value: 'Canine' },
+                ],
+                saveQuery: false,
+                queryName: ''
+            });
+            expect(q).toBe('document pdf type:arvados#collection cluster:c97qx is:pastVersion from:2017-08-01 has:"file size":"101mb" has:"Species":"Human" has:"Species":"Canine"');
+        });
+
         it('should add has:"key":"value" expression to query from same property key', () => {
             const searchValue = 'document pdf has:"file size":"101mb" has:"Species":"Canine"';
             const prevData = {
@@ -78,6 +102,7 @@ describe('search-bar-actions', () => {
                 cluster: undefined,
                 projectUuid: undefined,
                 inTrash: false,
+                pastVersions: false,
                 dateFrom: '',
                 dateTo: '',
                 properties: [
@@ -107,6 +132,7 @@ describe('search-bar-actions', () => {
                 cluster: undefined,
                 projectUuid: undefined,
                 inTrash: false,
+                pastVersions: false,
                 dateFrom: '',
                 dateTo: '',
                 properties: [
@@ -134,6 +160,7 @@ describe('search-bar-actions', () => {
                 cluster: undefined,
                 projectUuid: undefined,
                 inTrash: false,
+                pastVersions: false,
                 dateFrom: '',
                 dateTo: '',
                 properties: [
index d9dc0a64905aa5c3596e244f36b935e53bc7d4f4..b010af1448d9c410a64883c4863c0fc2e90b1a2f 100644 (file)
@@ -268,6 +268,7 @@ export const getQueryFromAdvancedData = (data: SearchBarAdvancedFormData, prevDa
             cluster: data.cluster,
             projectUuid: data.projectUuid,
             inTrash: data.inTrash,
+            pastVersions: data.pastVersions,
             dateFrom: data.dateFrom,
             dateTo: data.dateTo,
         };
@@ -282,6 +283,7 @@ export const getQueryFromAdvancedData = (data: SearchBarAdvancedFormData, prevDa
         ['cluster', 'cluster'],
         ['project', 'projectUuid'],
         [`is:${parser.States.TRASHED}`, 'inTrash'],
+        [`is:${parser.States.PAST_VERSION}`, 'pastVersions'],
         ['from', 'dateFrom'],
         ['to', 'dateTo']
     ];
@@ -307,6 +309,7 @@ export const getAdvancedDataFromQuery = (query: string, vocabulary?: Vocabulary)
         cluster: getValue(Keywords.CLUSTER),
         projectUuid: getValue(Keywords.PROJECT),
         inTrash: parser.isTrashed(tokens),
+        pastVersions: parser.isPastVersion(tokens),
         dateFrom: getValue(Keywords.FROM) || '',
         dateTo: getValue(Keywords.TO) || '',
         properties: vocabulary
index c9b7024b921ecb4e1c232779df420ce25c1fa34b..1d0618c6fcc936b1a8cc05db5b7716f0ceecee62 100644 (file)
@@ -20,7 +20,8 @@ export enum Keywords {
 }
 
 export enum States {
-    TRASHED = 'trashed'
+    TRASHED = 'trashed',
+    PAST_VERSION = 'pastVersion'
 }
 
 const keyValuePattern = (key: string) => new RegExp(`${key}:([^ ]*)`);
@@ -60,12 +61,16 @@ export const getProperties = (tokens: string[]) =>
     }, [] as Property[]);
 
 
-export const isTrashed = (tokens: string[]) => {
+export const isTrashed = (tokens: string[]) => isSomeState(States.TRASHED, tokens);
+
+export const isPastVersion = (tokens: string[]) => isSomeState(States.PAST_VERSION, tokens);
+
+const isSomeState = (state: string, tokens: string[]) => {
     for (const token of tokens) {
         const match = token.match(keyValuePattern(Keywords.IS)) || ['', ''];
         if (match) {
             const [, value] = match;
-            if(value === States.TRASHED) {
+            if(value === state) {
                 return true;
             }
         }
index f054a4e4e83637949ad60665ca17647fbbc7f7c4..6d2dce7ceae48662e2c177e9c95834b7ade1408e 100644 (file)
@@ -77,7 +77,8 @@ const getParams = (dataExplorer: DataExplorer, query: string, apiRevision: numbe
         typeFilters(dataExplorer.columns)
     ),
     order: getOrder(dataExplorer),
-    includeTrash: getAdvancedDataFromQuery(query).inTrash
+    includeTrash: getAdvancedDataFromQuery(query).inTrash,
+    includeOldVersions: getAdvancedDataFromQuery(query).pastVersions
 });
 
 const getOrder = (dataExplorer: DataExplorer) => {
index 90d8d977a2ef5103e8c227cd9935fddbee4a092c..8afa45325ee7ba211950ab3015fbf4fb76fe603a 100644 (file)
@@ -17,7 +17,7 @@ import { getProcess, Process, getProcessStatus, getProcessStatusColor, getProces
 import { ArvadosTheme } from '~/common/custom-theme';
 import { compose, Dispatch } from 'redux';
 import { WorkflowResource } from '~/models/workflow';
-import { ResourceStatus } from '~/views/workflow-panel/workflow-panel-view';
+import { ResourceStatus as WorkflowStatus } from '~/views/workflow-panel/workflow-panel-view';
 import { getUuidPrefix, openRunProcess } from '~/store/workflow-panel/workflow-panel-actions';
 import { openSharingDialog } from '~/store/sharing-dialog/sharing-dialog-actions';
 import { UserResource } from '~/models/user';
@@ -358,9 +358,9 @@ export const ResourceRunProcess = connect(
 
 const renderWorkflowStatus = (uuidPrefix: string, ownerUuid?: string) => {
     if (ownerUuid === getPublicUuid(uuidPrefix)) {
-        return renderStatus(ResourceStatus.PUBLIC);
+        return renderStatus(WorkflowStatus.PUBLIC);
     } else {
-        return renderStatus(ResourceStatus.PRIVATE);
+        return renderStatus(WorkflowStatus.PRIVATE);
     }
 };
 
@@ -442,6 +442,22 @@ export const ResourceType = connect(
         return { type: resource ? resource.kind : '' };
     })((props: { type: string }) => renderType(props.type));
 
+export const ResourceStatus = connect((state: RootState, props: { uuid: string }) => {
+        return { resource: getResource<GroupContentsResource>(props.uuid)(state.resources) };
+    })((props: { resource: GroupContentsResource }) =>
+        (props.resource && props.resource.kind === ResourceKind.COLLECTION)
+        ? <CollectionStatus uuid={props.resource.uuid} />
+        : <ProcessStatus uuid={props.resource.uuid} />
+    );
+
+export const CollectionStatus = connect((state: RootState, props: { uuid: string }) => {
+        return { collection: getResource<CollectionResource>(props.uuid)(state.resources) };
+    })((props: { collection: CollectionResource }) =>
+        (props.collection.uuid !== props.collection.currentVersionUuid)
+        ? <Typography>old version</Typography>
+        : <Typography>current</Typography>
+    );
+
 export const ProcessStatus = compose(
     connect((state: RootState, props: { uuid: string }) => {
         return { process: getProcess(props.uuid)(state.resources) };
index 837f13cb548b3144e8677f086030665cd02a366f..2eea38c4c85827466d2fcb1344432c20a714a702 100644 (file)
@@ -71,6 +71,12 @@ export const SearchBarTrashField = () =>
         component={CheckboxField}
         label="In trash" />;
 
+export const SearchBarPastVersionsField = () =>
+    <Field
+        name='pastVersions'
+        component={CheckboxField}
+        label="Past versions" />;
+
 export const SearchBarDateFromField = () =>
     <Field
         name='dateFrom'
index 71d32ad7e95dd51efa91ee4794b6e4172154cbc1..9f9688c345ad4f08c41b700901b9bb5eb73b8f88 100644 (file)
@@ -17,7 +17,7 @@ import { SearchBarAdvancedFormData } from '~/models/search-bar';
 import {
     SearchBarTypeField, SearchBarClusterField, SearchBarProjectField, SearchBarTrashField,
     SearchBarDateFromField, SearchBarDateToField, SearchBarPropertiesField,
-    SearchBarSaveSearchField, SearchBarQuerySearchField
+    SearchBarSaveSearchField, SearchBarQuerySearchField, SearchBarPastVersionsField
 } from '~/views-components/form-fields/search-bar-form-fields';
 import { treePickerActions } from "~/store/tree-picker/tree-picker-actions";
 
@@ -141,6 +141,9 @@ export const SearchBarAdvancedView = compose(
                                 <Grid item xs={5}>
                                     <SearchBarTrashField />
                                 </Grid>
+                                <Grid item xs={5}>
+                                    <SearchBarPastVersionsField />
+                                </Grid>
                             </Grid>
                             <IconButton onClick={closeAdvanceView} className={classes.closeIcon}>
                                 <CloseIcon />
index 43ca131396ddcd8063688c1a4d7cc6368d18f2dc..fbaba210e29b94cec6d32def6256c6eba116d342 100644 (file)
@@ -11,11 +11,12 @@ import { ContainerRequestState } from '~/models/container-request';
 import { SEARCH_RESULTS_PANEL_ID } from '~/store/search-results-panel/search-results-panel-actions';
 import { DataExplorer } from '~/views-components/data-explorer/data-explorer';
 import {
-    ProcessStatus, ResourceCluster,
+    ResourceCluster,
     ResourceFileSize,
     ResourceLastModifiedDate,
     ResourceName,
     ResourceOwner,
+    ResourceStatus,
     ResourceType
 } from '~/views-components/data-explorer/renderers';
 import { createTree } from '~/models/tree';
@@ -29,7 +30,6 @@ import { ArvadosTheme } from '~/common/custom-theme';
 export enum SearchResultsPanelColumnNames {
     CLUSTER = "Cluster",
     NAME = "Name",
-    PROJECT = "Project",
     STATUS = "Status",
     TYPE = 'Type',
     OWNER = "Owner",
@@ -66,19 +66,12 @@ export const searchResultsPanelColumns: DataColumns<string> = [
         filters: createTree(),
         render: (uuid: string) => <ResourceName uuid={uuid} />
     },
-    {
-        name: SearchResultsPanelColumnNames.PROJECT,
-        selected: true,
-        configurable: true,
-        filters: createTree(),
-        render: uuid => <ResourceFileSize uuid={uuid} />
-    },
     {
         name: SearchResultsPanelColumnNames.STATUS,
         selected: true,
         configurable: true,
         filters: createTree(),
-        render: uuid => <ProcessStatus uuid={uuid} />
+        render: uuid => <ResourceStatus uuid={uuid} />
     },
     {
         name: SearchResultsPanelColumnNames.TYPE,