[ARVADOS-WORKBENCH2] updated: 2.1.0-261-g21abfcba
Git user
git at public.arvados.org
Tue Mar 23 17:27:02 UTC 2021
Summary of changes:
src/common/labels.ts | 5 ++-
src/index.tsx | 6 ++-
.../context-menu/context-menu-actions.test.ts | 15 +++-----
src/store/context-menu/context-menu-actions.ts | 42 ++++++---------------
.../resource-type-filters.test.ts | 41 +++++++++++++++++++-
.../resource-type-filters/resource-type-filters.ts | 44 ++++++++++++++++++++--
.../side-panel-tree/side-panel-tree-actions.ts | 2 +-
.../action-sets/project-action-set.test.ts | 18 ++++++++-
.../context-menu/action-sets/project-action-set.ts | 22 +++++++----
.../action-sets/project-admin-action-set.ts | 15 +++++++-
src/views-components/context-menu/context-menu.tsx | 2 +
src/views-components/data-explorer/renderers.tsx | 8 ++--
src/views/project-panel/project-panel.tsx | 10 ++++-
13 files changed, 166 insertions(+), 64 deletions(-)
via 21abfcbaba4e8e735f353a1e3b030dd5dae8465b (commit)
from 407d1f609f40e8a7d21cf5846690b63706befaa4 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
commit 21abfcbaba4e8e735f353a1e3b030dd5dae8465b
Author: Ward Vandewege <ward at curii.com>
Date: Tue Mar 23 12:40:56 2021 -0400
17119: further changes after review feedback.
Arvados-DCO-1.1-Signed-off-by: Ward Vandewege <ward at curii.com>
diff --git a/src/common/labels.ts b/src/common/labels.ts
index c3c4fcd0..cfc2c52c 100644
--- a/src/common/labels.ts
+++ b/src/common/labels.ts
@@ -4,11 +4,14 @@
import { ResourceKind } from "~/models/resource";
-export const resourceLabel = (type: string) => {
+export const resourceLabel = (type: string, subtype = '') => {
switch (type) {
case ResourceKind.COLLECTION:
return "Data collection";
case ResourceKind.PROJECT:
+ if (subtype === "filter") {
+ return "Filter group";
+ }
return "Project";
case ResourceKind.PROCESS:
return "Process";
diff --git a/src/index.tsx b/src/index.tsx
index 31ae8564..522d8dc1 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -21,7 +21,7 @@ import { CustomTheme } from '~/common/custom-theme';
import { fetchConfig } from '~/common/config';
import { addMenuActionSet, ContextMenuKind } from '~/views-components/context-menu/context-menu';
import { rootProjectActionSet } from "~/views-components/context-menu/action-sets/root-project-action-set";
-import { projectActionSet, readOnlyProjectActionSet } from "~/views-components/context-menu/action-sets/project-action-set";
+import { filterGroupActionSet, projectActionSet, readOnlyProjectActionSet } from "~/views-components/context-menu/action-sets/project-action-set";
import { resourceActionSet } from '~/views-components/context-menu/action-sets/resource-action-set';
import { favoriteActionSet } from "~/views-components/context-menu/action-sets/favorite-action-set";
import { collectionFilesActionSet, readOnlyCollectionFilesActionSet } from '~/views-components/context-menu/action-sets/collection-files-action-set';
@@ -58,7 +58,7 @@ import { groupMemberActionSet } from '~/views-components/context-menu/action-set
import { linkActionSet } from '~/views-components/context-menu/action-sets/link-action-set';
import { loadFileViewersConfig } from '~/store/file-viewers/file-viewers-actions';
import { processResourceAdminActionSet } from '~/views-components/context-menu/action-sets/process-resource-admin-action-set';
-import { projectAdminActionSet } from '~/views-components/context-menu/action-sets/project-admin-action-set';
+import { filterGroupAdminActionSet, projectAdminActionSet } from '~/views-components/context-menu/action-sets/project-admin-action-set';
import { snackbarActions, SnackbarKind } from "~/store/snackbar/snackbar-actions";
import { openNotFoundDialog } from './store/not-found-panel/not-found-panel-action';
import { storeRedirects } from './common/redirect-to';
@@ -68,6 +68,7 @@ console.log(`Starting arvados [${getBuildInfo()}]`);
addMenuActionSet(ContextMenuKind.ROOT_PROJECT, rootProjectActionSet);
addMenuActionSet(ContextMenuKind.PROJECT, projectActionSet);
addMenuActionSet(ContextMenuKind.READONLY_PROJECT, readOnlyProjectActionSet);
+addMenuActionSet(ContextMenuKind.FILTER_GROUP, filterGroupActionSet);
addMenuActionSet(ContextMenuKind.RESOURCE, resourceActionSet);
addMenuActionSet(ContextMenuKind.FAVORITE, favoriteActionSet);
addMenuActionSet(ContextMenuKind.COLLECTION_FILES, collectionFilesActionSet);
@@ -96,6 +97,7 @@ addMenuActionSet(ContextMenuKind.GROUP_MEMBER, groupMemberActionSet);
addMenuActionSet(ContextMenuKind.COLLECTION_ADMIN, collectionAdminActionSet);
addMenuActionSet(ContextMenuKind.PROCESS_ADMIN, processResourceAdminActionSet);
addMenuActionSet(ContextMenuKind.PROJECT_ADMIN, projectAdminActionSet);
+addMenuActionSet(ContextMenuKind.FILTER_GROUP_ADMIN, filterGroupAdminActionSet);
storeRedirects();
diff --git a/src/store/context-menu/context-menu-actions.test.ts b/src/store/context-menu/context-menu-actions.test.ts
index 7f6326f7..179e3a3c 100644
--- a/src/store/context-menu/context-menu-actions.test.ts
+++ b/src/store/context-menu/context-menu-actions.test.ts
@@ -24,7 +24,7 @@ describe('context-menu-actions', () => {
it('should return the correct menu kind', () => {
const cases = [
- // resourceUuid, isAdminUser, isEditable, isTrashed, inFilterGroup, expected
+ // resourceUuid, isAdminUser, isEditable, isTrashed, readonly, expected
[headCollectionUuid, false, true, true, false, ContextMenuKind.TRASHED_COLLECTION],
[headCollectionUuid, false, true, false, false, ContextMenuKind.COLLECTION],
[headCollectionUuid, false, true, false, true, ContextMenuKind.READONLY_COLLECTION],
@@ -87,10 +87,10 @@ describe('context-menu-actions', () => {
[containerRequestUuid, true, false, false, true, ContextMenuKind.READONLY_PROCESS_RESOURCE],
]
- cases.forEach(([resourceUuid, isAdminUser, isEditable, isTrashed, inFilterGroup, expected]) => {
+ cases.forEach(([resourceUuid, isAdminUser, isEditable, isTrashed, readonly, expected]) => {
const initialState = {
properties: {
- [PROJECT_PANEL_CURRENT_UUID]: inFilterGroup ? filterGroupUuid : projectUuid,
+ [PROJECT_PANEL_CURRENT_UUID]: projectUuid,
},
resources: {
[headCollectionUuid]: {
@@ -133,20 +133,15 @@ describe('context-menu-actions', () => {
isAdmin: isAdminUser,
},
},
- router: {
- location: {
- pathname: inFilterGroup ? "/projects/" + filterGroupUuid : "",
- },
- },
};
const store = mockStore(initialState);
let menuKind: any;
try {
- menuKind = store.dispatch<any>(resourceUuidToContextMenuKind(resourceUuid as string))
+ menuKind = store.dispatch<any>(resourceUuidToContextMenuKind(resourceUuid as string, readonly as boolean))
expect(menuKind).toBe(expected);
} catch (err) {
- throw new Error(`menuKind for resource ${JSON.stringify(initialState.resources[resourceUuid as string])} expected to be ${expected} but got ${menuKind}.`);
+ throw new Error(`menuKind for resource ${JSON.stringify(initialState.resources[resourceUuid as string])} readonly: ${readonly} expected to be ${expected} but got ${menuKind}.`);
}
});
});
diff --git a/src/store/context-menu/context-menu-actions.ts b/src/store/context-menu/context-menu-actions.ts
index f8049a5c..83335f83 100644
--- a/src/store/context-menu/context-menu-actions.ts
+++ b/src/store/context-menu/context-menu-actions.ts
@@ -20,9 +20,6 @@ import { ProcessResource } from '~/models/process';
import { CollectionResource } from '~/models/collection';
import { GroupClass, GroupResource } from '~/models/group';
import { GroupContentsResource } from '~/services/groups-service/groups-service';
-import { getProjectPanelCurrentUuid } from '~/store/project-panel/project-panel-action';
-import { matchProjectRoute } from '~/routes/routes';
-import { RouterState } from "react-router-redux";
export const contextMenuActions = unionize({
OPEN_CONTEXT_MENU: ofType<{ position: ContextMenuPosition, resource: ContextMenuResource }>(),
@@ -204,38 +201,23 @@ export const openProcessContextMenu = (event: React.MouseEvent<HTMLElement>, pro
}
};
-export const isProjectRoute = (router: RouterState) => {
- const pathname = router.location ? router.location.pathname : '';
- const matchProject = matchProjectRoute(pathname);
- return Boolean(matchProject);
-};
-
-export const resourceUuidToContextMenuKind = (uuid: string) =>
+export const resourceUuidToContextMenuKind = (uuid: string, readonly = false) =>
(dispatch: Dispatch, getState: () => RootState) => {
const { isAdmin: isAdminUser, uuid: userUuid } = getState().auth.user!;
const kind = extractUuidKind(uuid);
const resource = getResourceWithEditableStatus<GroupResource & EditableResource>(uuid, userUuid)(getState().resources);
- // When viewing the contents of a filter group, all contents should be treated as read only.
- let inFilterGroup = false;
- const { router } = getState();
- if (isProjectRoute(router)) {
- const projectUuid = getProjectPanelCurrentUuid(getState());
- if (projectUuid !== undefined) {
- const project = getResource<GroupResource>(projectUuid)(getState().resources);
- if (project && project.groupClass === GroupClass.FILTER) {
- inFilterGroup = true;
- }
- }
- }
-
- const isEditable = (isAdminUser || (resource || {} as EditableResource).isEditable) && !inFilterGroup;
+ const isEditable = (isAdminUser || (resource || {} as EditableResource).isEditable) && !readonly;
switch (kind) {
case ResourceKind.PROJECT:
- return (isAdminUser && !inFilterGroup)
- ? ContextMenuKind.PROJECT_ADMIN
+ return (isAdminUser && !readonly)
+ ? (resource && resource.groupClass !== GroupClass.FILTER)
+ ? ContextMenuKind.PROJECT_ADMIN
+ : ContextMenuKind.FILTER_GROUP_ADMIN
: isEditable
- ? ContextMenuKind.PROJECT
+ ? (resource && resource.groupClass !== GroupClass.FILTER)
+ ? ContextMenuKind.PROJECT
+ : ContextMenuKind.FILTER_GROUP
: ContextMenuKind.READONLY_PROJECT;
case ResourceKind.COLLECTION:
const c = getResource<CollectionResource>(uuid)(getState().resources);
@@ -246,15 +228,15 @@ export const resourceUuidToContextMenuKind = (uuid: string) =>
? ContextMenuKind.OLD_VERSION_COLLECTION
: (isTrashed && isEditable)
? ContextMenuKind.TRASHED_COLLECTION
- : (isAdminUser && !inFilterGroup)
+ : (isAdminUser && !readonly)
? ContextMenuKind.COLLECTION_ADMIN
: isEditable
? ContextMenuKind.COLLECTION
: ContextMenuKind.READONLY_COLLECTION;
case ResourceKind.PROCESS:
- return (isAdminUser && !inFilterGroup)
+ return (isAdminUser && !readonly)
? ContextMenuKind.PROCESS_ADMIN
- : inFilterGroup
+ : readonly
? ContextMenuKind.READONLY_PROCESS_RESOURCE
: ContextMenuKind.PROCESS_RESOURCE;
case ResourceKind.USER:
diff --git a/src/store/resource-type-filters/resource-type-filters.test.ts b/src/store/resource-type-filters/resource-type-filters.test.ts
index 2f4d3cad..95d0349f 100644
--- a/src/store/resource-type-filters/resource-type-filters.test.ts
+++ b/src/store/resource-type-filters/resource-type-filters.test.ts
@@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0
-import { getInitialResourceTypeFilters, serializeResourceTypeFilters, ObjectTypeFilter, CollectionTypeFilter, ProcessTypeFilter } from './resource-type-filters';
+import { getInitialResourceTypeFilters, serializeResourceTypeFilters, ObjectTypeFilter, CollectionTypeFilter, ProcessTypeFilter, GroupTypeFilter } from './resource-type-filters';
import { ResourceKind } from '~/models/resource';
import { deselectNode } from '~/models/tree';
import { pipe } from 'lodash/fp';
@@ -73,4 +73,43 @@ describe("serializeResourceTypeFilters", () => {
expect(serializedFilters)
.toEqual(`["uuid","is_a",["${ResourceKind.PROCESS}"]],["container_requests.requesting_container_uuid","!=",null]`);
});
+
+ it("should serialize all project types", () => {
+ const filters = pipe(
+ () => getInitialResourceTypeFilters(),
+ deselectNode(ObjectTypeFilter.PROCESS),
+ deselectNode(ObjectTypeFilter.COLLECTION),
+ )();
+
+ const serializedFilters = serializeResourceTypeFilters(filters);
+ expect(serializedFilters)
+ .toEqual(`["uuid","is_a",["${ResourceKind.GROUP}"]]`);
+ });
+
+ it("should serialize filter groups", () => {
+ const filters = pipe(
+ () => getInitialResourceTypeFilters(),
+ deselectNode(GroupTypeFilter.PROJECT)
+ deselectNode(ObjectTypeFilter.PROCESS),
+ deselectNode(ObjectTypeFilter.COLLECTION),
+ )();
+
+ const serializedFilters = serializeResourceTypeFilters(filters);
+ expect(serializedFilters)
+ .toEqual(`["uuid","is_a",["${ResourceKind.GROUP}"]],["groups.group_class","=","filter"]`);
+ });
+
+ it("should serialize projects (normal)", () => {
+ const filters = pipe(
+ () => getInitialResourceTypeFilters(),
+ deselectNode(GroupTypeFilter.FILTER_GROUP)
+ deselectNode(ObjectTypeFilter.PROCESS),
+ deselectNode(ObjectTypeFilter.COLLECTION),
+ )();
+
+ const serializedFilters = serializeResourceTypeFilters(filters);
+ expect(serializedFilters)
+ .toEqual(`["uuid","is_a",["${ResourceKind.GROUP}"]],["groups.group_class","=","project"]`);
+ });
+
});
diff --git a/src/store/resource-type-filters/resource-type-filters.ts b/src/store/resource-type-filters/resource-type-filters.ts
index ef1198bc..26db4e9e 100644
--- a/src/store/resource-type-filters/resource-type-filters.ts
+++ b/src/store/resource-type-filters/resource-type-filters.ts
@@ -25,7 +25,12 @@ export enum ProcessStatusFilter {
export enum ObjectTypeFilter {
PROJECT = 'Project',
PROCESS = 'Process',
- COLLECTION = 'Data Collection',
+ COLLECTION = 'Data collection',
+}
+
+export enum GroupTypeFilter {
+ PROJECT = 'Project (normal)',
+ FILTER_GROUP = 'Filter group',
}
export enum CollectionTypeFilter {
@@ -62,7 +67,11 @@ export const getSimpleObjectTypeFilters = pipe(
// causing compile issues.
export const getInitialResourceTypeFilters = pipe(
(): DataTableFilters => createTree<DataTableFilterItem>(),
- initFilter(ObjectTypeFilter.PROJECT),
+ pipe(
+ initFilter(ObjectTypeFilter.PROJECT),
+ initFilter(GroupTypeFilter.PROJECT, ObjectTypeFilter.PROJECT),
+ initFilter(GroupTypeFilter.FILTER_GROUP, ObjectTypeFilter.PROJECT),
+ ),
pipe(
initFilter(ObjectTypeFilter.PROCESS),
initFilter(ProcessTypeFilter.MAIN_PROCESS, ObjectTypeFilter.PROCESS),
@@ -124,10 +133,14 @@ const objectTypeToResourceKind = (type: ObjectTypeFilter) => {
};
const serializeObjectTypeFilters = ({ fb, selectedFilters }: ReturnType<typeof createFiltersBuilder>) => {
+ const groupFilters = getMatchingFilters(values(GroupTypeFilter), selectedFilters);
const collectionFilters = getMatchingFilters(values(CollectionTypeFilter), selectedFilters);
const processFilters = getMatchingFilters(values(ProcessTypeFilter), selectedFilters);
const typeFilters = pipe(
() => new Set(getMatchingFilters(values(ObjectTypeFilter), selectedFilters)),
+ set => groupFilters.length > 0
+ ? set.add(ObjectTypeFilter.PROJECT)
+ : set,
set => collectionFilters.length > 0
? set.add(ObjectTypeFilter.COLLECTION)
: set,
@@ -182,6 +195,30 @@ const buildCollectionTypeFilters = ({ fb, filters }: { fb: FilterBuilder, filter
}
};
+const serializeGroupTypeFilters = ({ fb, selectedFilters }: ReturnType<typeof createFiltersBuilder>) => pipe(
+ () => getMatchingFilters(values(GroupTypeFilter), selectedFilters),
+ filters => filters,
+ mappedFilters => ({
+ fb: buildGroupTypeFilters({ fb, filters: mappedFilters, use_prefix: true }),
+ selectedFilters
+ })
+)();
+
+const GROUP_TYPES = values(GroupTypeFilter);
+
+const buildGroupTypeFilters = ({ fb, filters, use_prefix }: { fb: FilterBuilder, filters: string[], use_prefix: boolean }) => {
+ switch (true) {
+ case filters.length === 0 || filters.length === GROUP_TYPES.length:
+ return fb;
+ case includes(GroupTypeFilter.PROJECT, filters):
+ return fb.addEqual('groups.group_class', 'project');
+ case includes(GroupTypeFilter.FILTER_GROUP, filters):
+ return fb.addEqual('groups.group_class', 'filter');
+ default:
+ return fb;
+ }
+};
+
const serializeProcessTypeFilters = ({ fb, selectedFilters }: ReturnType<typeof createFiltersBuilder>) => pipe(
() => getMatchingFilters(values(ProcessTypeFilter), selectedFilters),
filters => filters,
@@ -210,6 +247,7 @@ const buildProcessTypeFilters = ({ fb, filters, use_prefix }: { fb: FilterBuilde
export const serializeResourceTypeFilters = pipe(
createFiltersBuilder,
serializeObjectTypeFilters,
+ serializeGroupTypeFilters,
serializeCollectionTypeFilters,
serializeProcessTypeFilters,
({ fb }) => fb.getFilters(),
@@ -260,4 +298,4 @@ export const buildProcessStatusFilters = ( fb:FilterBuilder, activeStatusFilter:
}
}
return fb;
-};
\ No newline at end of file
+};
diff --git a/src/store/side-panel-tree/side-panel-tree-actions.ts b/src/store/side-panel-tree/side-panel-tree-actions.ts
index ff506103..05d61927 100644
--- a/src/store/side-panel-tree/side-panel-tree-actions.ts
+++ b/src/store/side-panel-tree/side-panel-tree-actions.ts
@@ -112,7 +112,7 @@ const loadSharedRoot = async (dispatch: Dispatch, getState: () => RootState, ser
const params = {
filters: `[${new FilterBuilder()
.addIsA('uuid', ResourceKind.PROJECT)
- .addEqual('group_class', GroupClass.PROJECT)
+ .addIn('group_class', [GroupClass.PROJECT, GroupClass.FILTER])
.addDistinct('uuid', getState().auth.config.uuidPrefix + '-j7d0g-publicfavorites')
.getFilters()}]`,
order: new OrderBuilder<ProjectResource>()
diff --git a/src/views-components/context-menu/action-sets/project-action-set.test.ts b/src/views-components/context-menu/action-sets/project-action-set.test.ts
index fd328221..1932194c 100644
--- a/src/views-components/context-menu/action-sets/project-action-set.test.ts
+++ b/src/views-components/context-menu/action-sets/project-action-set.test.ts
@@ -2,11 +2,12 @@
//
// SPDX-License-Identifier: AGPL-3.0
-import { projectActionSet, readOnlyProjectActionSet } from "./project-action-set";
+import { filterGroupActionSet, projectActionSet, readOnlyProjectActionSet } from "./project-action-set";
describe('project-action-set', () => {
const flattProjectActionSet = projectActionSet.reduce((prev, next) => prev.concat(next), []);
const flattReadOnlyProjectActionSet = readOnlyProjectActionSet.reduce((prev, next) => prev.concat(next), []);
+ const flattFilterGroupActionSet = filterGroupActionSet.reduce((prev, next) => prev.concat(next), []);
describe('projectActionSet', () => {
it('should not be empty', () => {
@@ -33,4 +34,17 @@ describe('project-action-set', () => {
.not.toEqual(expect.arrayContaining(flattProjectActionSet));
})
});
-});
\ No newline at end of file
+
+ describe('filterGroupActionSet', () => {
+ it('should not be empty', () => {
+ // then
+ expect(flattFilterGroupActionSet.length).toBeGreaterThan(0);
+ });
+
+ it('should not contain projectActionSet items', () => {
+ // then
+ expect(flattFilterGroupActionSet)
+ .not.toEqual(expect.arrayContaining(flattProjectActionSet));
+ })
+ });
+});
diff --git a/src/views-components/context-menu/action-sets/project-action-set.ts b/src/views-components/context-menu/action-sets/project-action-set.ts
index 57ba0ea3..800f57d9 100644
--- a/src/views-components/context-menu/action-sets/project-action-set.ts
+++ b/src/views-components/context-menu/action-sets/project-action-set.ts
@@ -66,16 +66,9 @@ export const readOnlyProjectActionSet: ContextMenuActionSet = [[
},
]];
-export const projectActionSet: ContextMenuActionSet = [
+export const filterGroupActionSet: ContextMenuActionSet = [
[
...readOnlyProjectActionSet.reduce((prev, next) => prev.concat(next), []),
- {
- icon: NewProjectIcon,
- name: "New project",
- execute: (dispatch, resource) => {
- dispatch<any>(openProjectCreateDialog(resource.uuid));
- }
- },
{
icon: RenameIcon,
name: "Edit project",
@@ -106,3 +99,16 @@ export const projectActionSet: ContextMenuActionSet = [
},
]
];
+
+export const projectActionSet: ContextMenuActionSet = [
+ [
+ ...filterGroupActionSet.reduce((prev, next) => prev.concat(next), []),
+ {
+ icon: NewProjectIcon,
+ name: "New project",
+ execute: (dispatch, resource) => {
+ dispatch<any>(openProjectCreateDialog(resource.uuid));
+ }
+ },
+ ]
+];
diff --git a/src/views-components/context-menu/action-sets/project-admin-action-set.ts b/src/views-components/context-menu/action-sets/project-admin-action-set.ts
index a3a8ce79..982a7883 100644
--- a/src/views-components/context-menu/action-sets/project-admin-action-set.ts
+++ b/src/views-components/context-menu/action-sets/project-admin-action-set.ts
@@ -7,7 +7,7 @@ import { TogglePublicFavoriteAction } from "~/views-components/context-menu/acti
import { togglePublicFavorite } from "~/store/public-favorites/public-favorites-actions";
import { publicFavoritePanelActions } from "~/store/public-favorites-panel/public-favorites-action";
-import { projectActionSet } from "~/views-components/context-menu/action-sets/project-action-set";
+import { projectActionSet, filterGroupActionSet } from "~/views-components/context-menu/action-sets/project-action-set";
export const projectAdminActionSet: ContextMenuActionSet = [[
...projectActionSet.reduce((prev, next) => prev.concat(next), []),
@@ -21,3 +21,16 @@ export const projectAdminActionSet: ContextMenuActionSet = [[
}
}
]];
+
+export const filterGroupAdminActionSet: ContextMenuActionSet = [[
+ ...filterGroupActionSet.reduce((prev, next) => prev.concat(next), []),
+ {
+ component: TogglePublicFavoriteAction,
+ name: 'TogglePublicFavoriteAction',
+ execute: (dispatch, resource) => {
+ dispatch<any>(togglePublicFavorite(resource)).then(() => {
+ dispatch<any>(publicFavoritePanelActions.REQUEST_ITEMS());
+ });
+ }
+ }
+]];
diff --git a/src/views-components/context-menu/context-menu.tsx b/src/views-components/context-menu/context-menu.tsx
index 7f2a29f8..ee87d71a 100644
--- a/src/views-components/context-menu/context-menu.tsx
+++ b/src/views-components/context-menu/context-menu.tsx
@@ -67,8 +67,10 @@ export enum ContextMenuKind {
API_CLIENT_AUTHORIZATION = "ApiClientAuthorization",
ROOT_PROJECT = "RootProject",
PROJECT = "Project",
+ FILTER_GROUP = "FilterGroup",
READONLY_PROJECT = 'ReadOnlyProject',
PROJECT_ADMIN = "ProjectAdmin",
+ FILTER_GROUP_ADMIN = "FilterGroupAdmin",
RESOURCE = "Resource",
FAVORITE = "Favorite",
TRASH = "Trash",
diff --git a/src/views-components/data-explorer/renderers.tsx b/src/views-components/data-explorer/renderers.tsx
index 28a6f253..93abb15e 100644
--- a/src/views-components/data-explorer/renderers.tsx
+++ b/src/views-components/data-explorer/renderers.tsx
@@ -468,16 +468,16 @@ export const ResourceOwnerWithName =
</Typography>;
});
-const renderType = (type: string) =>
+const renderType = (type: string, subtype: string) =>
<Typography noWrap>
- {resourceLabel(type)}
+ {resourceLabel(type, subtype)}
</Typography>;
export const ResourceType = connect(
(state: RootState, props: { uuid: string }) => {
const resource = getResource<GroupContentsResource>(props.uuid)(state.resources);
- return { type: resource ? resource.kind : '' };
- })((props: { type: string }) => renderType(props.type));
+ return { type: resource ? resource.kind : '', subtype: resource && resource.kind === ResourceKind.GROUP ? resource.groupClass : '' };
+ })((props: { type: string, subtype: string }) => renderType(props.type, props.subtype));
export const ResourceStatus = connect((state: RootState, props: { uuid: string }) => {
return { resource: getResource<GroupContentsResource>(props.uuid)(state.resources) };
diff --git a/src/views/project-panel/project-panel.tsx b/src/views/project-panel/project-panel.tsx
index 47dbd9b0..35a7f9c1 100644
--- a/src/views/project-panel/project-panel.tsx
+++ b/src/views/project-panel/project-panel.tsx
@@ -44,6 +44,7 @@ import {
getInitialProcessStatusFilters
} from '~/store/resource-type-filters/resource-type-filters';
import { GroupContentsResource } from '~/services/groups-service/groups-service';
+import { GroupClass, GroupResource } from '~/models/group';
type CssRules = 'root' | "button";
@@ -167,7 +168,14 @@ export const ProjectPanel = withStyles(styles)(
handleContextMenu = (event: React.MouseEvent<HTMLElement>, resourceUuid: string) => {
const { resources } = this.props;
const resource = getResource<GroupContentsResource>(resourceUuid)(resources);
- const menuKind = this.props.dispatch<any>(resourceUuidToContextMenuKind(resourceUuid));
+ // When viewing the contents of a filter group, all contents should be treated as read only.
+ let readonly = false;
+ const project = getResource<GroupResource>(this.props.currentItemId)(resources);
+ if (project && project.groupClass === GroupClass.FILTER) {
+ readonly = true;
+ }
+
+ const menuKind = this.props.dispatch<any>(resourceUuidToContextMenuKind(resourceUuid, readonly));
if (menuKind && resource) {
this.props.dispatch<any>(openContextMenu(event, {
name: resource.name,
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list