import { userActionSet } from '~/views-components/context-menu/action-sets/user-action-set';
import { computeNodeActionSet } from '~/views-components/context-menu/action-sets/compute-node-action-set';
import { apiClientAuthorizationActionSet } from '~/views-components/context-menu/action-sets/api-client-authorization-action-set';
+import { groupActionSet } from '~/views-components/context-menu/action-sets/group-action-set';
+import { groupMemberActionSet } from '~/views-components/context-menu/action-sets/group-member-action-set';
+ import { linkActionSet } from '~/views-components/context-menu/action-sets/link-action-set';
console.log(`Starting arvados [${getBuildInfo()}]`);
addMenuActionSet(ContextMenuKind.VIRTUAL_MACHINE, virtualMachineActionSet);
addMenuActionSet(ContextMenuKind.KEEP_SERVICE, keepServiceActionSet);
addMenuActionSet(ContextMenuKind.USER, userActionSet);
+ addMenuActionSet(ContextMenuKind.LINK, linkActionSet);
addMenuActionSet(ContextMenuKind.NODE, computeNodeActionSet);
addMenuActionSet(ContextMenuKind.API_CLIENT_AUTHORIZATION, apiClientAuthorizationActionSet);
+addMenuActionSet(ContextMenuKind.GROUPS, groupActionSet);
+addMenuActionSet(ContextMenuKind.GROUP_MEMBER, groupMemberActionSet);
fetchConfig()
.then(({ config, apiHost }) => {
//
// SPDX-License-Identifier: AGPL-3.0
- import { Resource, ResourceKind } from "./resource";
-import { Resource } from "./resource";
import { TagProperty } from "~/models/tag";
-import { ResourceKind } from '~/models/resource';
++import { Resource, ResourceKind } from '~/models/resource';
export interface LinkResource extends Resource {
headUuid: string;
+ headKind: ResourceKind;
tailUuid: string;
+ tailKind: string;
linkClass: string;
name: string;
properties: TagProperty;
+ kind: ResourceKind.LINK;
}
export enum LinkClass {
STAR = 'star',
TAG = 'tag',
PERMISSION = 'permission',
+ PRESET = 'preset',
}
import * as Routes from '~/routes/routes';
import * as WorkbenchActions from '~/store/workbench/workbench-actions';
import { navigateToRootProject } from '~/store/navigation/navigation-action';
+ import { dialogActions } from '~/store/dialog/dialog-actions';
export const addRouteChangeHandlers = (history: History, store: RootStore) => {
const handler = handleLocationChange(store);
const searchResultsMatch = Routes.matchSearchResultsRoute(pathname);
const sharedWithMeMatch = Routes.matchSharedWithMeRoute(pathname);
const runProcessMatch = Routes.matchRunProcessRoute(pathname);
- const virtualMachineMatch = Routes.matchVirtualMachineRoute(pathname);
+ const virtualMachineUserMatch = Routes.matchUserVirtualMachineRoute(pathname);
+ const virtualMachineAdminMatch = Routes.matchAdminVirtualMachineRoute(pathname);
const workflowMatch = Routes.matchWorkflowRoute(pathname);
- const sshKeysMatch = Routes.matchSshKeysRoute(pathname);
+ const sshKeysUserMatch = Routes.matchSshKeysUserRoute(pathname);
+ const sshKeysAdminMatch = Routes.matchSshKeysAdminRoute(pathname);
const keepServicesMatch = Routes.matchKeepServicesRoute(pathname);
const computeNodesMatch = Routes.matchComputeNodesRoute(pathname);
const apiClientAuthorizationsMatch = Routes.matchApiClientAuthorizationsRoute(pathname);
const myAccountMatch = Routes.matchMyAccountRoute(pathname);
const userMatch = Routes.matchUsersRoute(pathname);
+ const groupsMatch = Routes.matchGroupsRoute(pathname);
+ const groupDetailsMatch = Routes.matchGroupDetailsRoute(pathname);
+ const linksMatch = Routes.matchLinksRoute(pathname);
+
+ store.dispatch(dialogActions.CLOSE_ALL_DIALOGS());
if (projectMatch) {
store.dispatch(WorkbenchActions.loadProject(projectMatch.params.id));
store.dispatch(WorkbenchActions.loadWorkflow);
} else if (searchResultsMatch) {
store.dispatch(WorkbenchActions.loadSearchResults);
- } else if (virtualMachineMatch) {
+ } else if (virtualMachineUserMatch) {
+ store.dispatch(WorkbenchActions.loadVirtualMachines);
+ } else if (virtualMachineAdminMatch) {
store.dispatch(WorkbenchActions.loadVirtualMachines);
- } else if(repositoryMatch) {
+ } else if (repositoryMatch) {
store.dispatch(WorkbenchActions.loadRepositories);
- } else if (sshKeysMatch) {
+ } else if (sshKeysUserMatch) {
+ store.dispatch(WorkbenchActions.loadSshKeys);
+ } else if (sshKeysAdminMatch) {
store.dispatch(WorkbenchActions.loadSshKeys);
} else if (keepServicesMatch) {
store.dispatch(WorkbenchActions.loadKeepServices);
store.dispatch(WorkbenchActions.loadApiClientAuthorizations);
} else if (myAccountMatch) {
store.dispatch(WorkbenchActions.loadMyAccount);
- }else if (userMatch) {
+ } else if (userMatch) {
store.dispatch(WorkbenchActions.loadUsers);
+ } else if (groupsMatch) {
+ store.dispatch(WorkbenchActions.loadGroupsPanel);
+ } else if (groupDetailsMatch) {
+ store.dispatch(WorkbenchActions.loadGroupDetailsPanel(groupDetailsMatch.params.id));
+ } else if (linksMatch) {
+ store.dispatch(WorkbenchActions.loadLinks);
}
};
REPOSITORIES: '/repositories',
SHARED_WITH_ME: '/shared-with-me',
RUN_PROCESS: '/run-process',
- VIRTUAL_MACHINES: '/virtual-machines',
+ VIRTUAL_MACHINES_ADMIN: '/virtual-machines-admin',
+ VIRTUAL_MACHINES_USER: '/virtual-machines-user',
WORKFLOWS: '/workflows',
SEARCH_RESULTS: '/search-results',
- SSH_KEYS: `/ssh-keys`,
+ SSH_KEYS_ADMIN: `/ssh-keys-admin`,
+ SSH_KEYS_USER: `/ssh-keys-user`,
MY_ACCOUNT: '/my-account',
KEEP_SERVICES: `/keep-services`,
COMPUTE_NODES: `/nodes`,
USERS: '/users',
API_CLIENT_AUTHORIZATIONS: `/api_client_authorizations`,
+ GROUPS: '/groups',
+ GROUP_DETAILS: `/group/:id(${RESOURCE_UUID_PATTERN})`,
+ LINKS: '/links'
};
export const getResourceUrl = (uuid: string) => {
export const getProcessLogUrl = (uuid: string) => `/process-logs/${uuid}`;
+export const getGroupUrl = (uuid: string) => `/group/${uuid}`;
+
export interface ResourceRouteParams {
id: string;
}
export const matchSearchResultsRoute = (route: string) =>
matchPath<ResourceRouteParams>(route, { path: Routes.SEARCH_RESULTS });
- export const matchVirtualMachineRoute = (route: string) =>
- matchPath<ResourceRouteParams>(route, { path: Routes.VIRTUAL_MACHINES });
+ export const matchUserVirtualMachineRoute = (route: string) =>
+ matchPath<ResourceRouteParams>(route, { path: Routes.VIRTUAL_MACHINES_USER });
+
+ export const matchAdminVirtualMachineRoute = (route: string) =>
+ matchPath<ResourceRouteParams>(route, { path: Routes.VIRTUAL_MACHINES_ADMIN });
export const matchRepositoriesRoute = (route: string) =>
matchPath<ResourceRouteParams>(route, { path: Routes.REPOSITORIES });
- export const matchSshKeysRoute = (route: string) =>
- matchPath(route, { path: Routes.SSH_KEYS });
+ export const matchSshKeysUserRoute = (route: string) =>
+ matchPath(route, { path: Routes.SSH_KEYS_USER });
+
+ export const matchSshKeysAdminRoute = (route: string) =>
+ matchPath(route, { path: Routes.SSH_KEYS_ADMIN });
export const matchMyAccountRoute = (route: string) =>
matchPath(route, { path: Routes.MY_ACCOUNT });
export const matchApiClientAuthorizationsRoute = (route: string) =>
matchPath(route, { path: Routes.API_CLIENT_AUTHORIZATIONS });
- matchPath(route, { path: Routes.LINKS });
+export const matchGroupsRoute = (route: string) =>
+ matchPath(route, { path: Routes.GROUPS });
+
+export const matchGroupDetailsRoute = (route: string) =>
+ matchPath<ResourceRouteParams>(route, { path: Routes.GROUP_DETAILS });
++
+ export const matchLinksRoute = (route: string) =>
++ matchPath(route, { path: Routes.LINKS });
import { getCollectionUrl } from "~/models/collection";
import { getProjectUrl } from "~/models/project";
import { SidePanelTreeCategory } from '../side-panel-tree/side-panel-tree-actions';
-import { Routes, getProcessUrl, getProcessLogUrl } from '~/routes/routes';
+import { Routes, getProcessUrl, getProcessLogUrl, getGroupUrl } from '~/routes/routes';
import { RootState } from '~/store/store';
import { ServiceRepository } from '~/services/services';
+import { GROUPS_PANEL_LABEL } from '~/store/breadcrumbs/breadcrumbs-actions';
export const navigateTo = (uuid: string) =>
async (dispatch: Dispatch) => {
dispatch<any>(navigateToCollection(uuid));
} else if (kind === ResourceKind.CONTAINER_REQUEST) {
dispatch<any>(navigateToProcess(uuid));
+ } else if (kind === ResourceKind.VIRTUAL_MACHINE) {
+ dispatch<any>(navigateToAdminVirtualMachines);
}
if (uuid === SidePanelTreeCategory.FAVORITES) {
dispatch<any>(navigateToFavorites);
dispatch(navigateToWorkflows);
} else if (uuid === SidePanelTreeCategory.TRASH) {
dispatch(navigateToTrash);
+ } else if (uuid === GROUPS_PANEL_LABEL) {
+ dispatch(navigateToGroups);
}
};
export const navigateToSearchResults = push(Routes.SEARCH_RESULTS);
- export const navigateToVirtualMachines = push(Routes.VIRTUAL_MACHINES);
+ export const navigateToUserVirtualMachines = push(Routes.VIRTUAL_MACHINES_USER);
+
+ export const navigateToAdminVirtualMachines = push(Routes.VIRTUAL_MACHINES_ADMIN);
export const navigateToRepositories = push(Routes.REPOSITORIES);
- export const navigateToSshKeys= push(Routes.SSH_KEYS);
+ export const navigateToSshKeysAdmin= push(Routes.SSH_KEYS_ADMIN);
+
+ export const navigateToSshKeysUser= push(Routes.SSH_KEYS_USER);
export const navigateToMyAccount = push(Routes.MY_ACCOUNT);
export const navigateToApiClientAuthorizations = push(Routes.API_CLIENT_AUTHORIZATIONS);
-export const navigateToLinks = push(Routes.LINKS);
+export const navigateToGroups = push(Routes.GROUPS);
+
+export const navigateToGroupDetails = compose(push, getGroupUrl);
++
++export const navigateToLinks = push(Routes.LINKS);
import { USERS_PANEL_ID } from '~/store/users/users-actions';
import { computeNodesReducer } from '~/store/compute-nodes/compute-nodes-reducer';
import { apiClientAuthorizationsReducer } from '~/store/api-client-authorizations/api-client-authorizations-reducer';
+import { GroupsPanelMiddlewareService } from '~/store/groups-panel/groups-panel-middleware-service';
+import { GROUPS_PANEL_ID } from '~/store/groups-panel/groups-panel-actions';
+import { GroupDetailsPanelMiddlewareService } from '~/store/group-details-panel/group-details-panel-middleware-service';
+import { GROUP_DETAILS_PANEL_ID } from '~/store/group-details-panel/group-details-panel-actions';
+ import { LINK_PANEL_ID } from '~/store/link-panel/link-panel-actions';
+ import { LinkMiddlewareService } from '~/store/link-panel/link-panel-middleware-service';
const composeEnhancers =
(process.env.NODE_ENV === 'development' &&
const userPanelMiddleware = dataExplorerMiddleware(
new UserMiddlewareService(services, USERS_PANEL_ID)
);
+ const groupsPanelMiddleware = dataExplorerMiddleware(
+ new GroupsPanelMiddlewareService(services, GROUPS_PANEL_ID)
+ );
+ const groupDetailsPanelMiddleware = dataExplorerMiddleware(
+ new GroupDetailsPanelMiddlewareService(services, GROUP_DETAILS_PANEL_ID)
+ );
+
+ const linkPanelMiddleware = dataExplorerMiddleware(
+ new LinkMiddlewareService(services, LINK_PANEL_ID)
+ );
const middlewares: Middleware[] = [
routerMiddleware(history),
thunkMiddleware.withExtraArgument(services),
sharedWithMePanelMiddleware,
workflowPanelMiddleware,
userPanelMiddleware,
+ groupsPanelMiddleware,
+ groupDetailsPanelMiddleware,
+ linkPanelMiddleware
];
const enhancer = composeEnhancers(applyMiddleware(...middlewares));
return createStore(rootReducer, enhancer);
import { projectPanelColumns } from '~/views/project-panel/project-panel';
import { favoritePanelColumns } from '~/views/favorite-panel/favorite-panel';
import { matchRootRoute } from '~/routes/routes';
-import { setSidePanelBreadcrumbs, setProcessBreadcrumbs, setSharedWithMeBreadcrumbs, setTrashBreadcrumbs, setBreadcrumbs } from '~/store/breadcrumbs/breadcrumbs-actions';
+import { setSidePanelBreadcrumbs, setProcessBreadcrumbs, setSharedWithMeBreadcrumbs, setTrashBreadcrumbs, setBreadcrumbs, setGroupDetailsBreadcrumbs, setGroupsBreadcrumbs } from '~/store/breadcrumbs/breadcrumbs-actions';
import { navigateToProject } from '~/store/navigation/navigation-action';
import { MoveToFormDialogData } from '~/store/move-to-dialog/move-to-dialog';
import { ServiceRepository } from '~/services/services';
import { loadRepositoriesPanel } from '~/store/repositories/repositories-actions';
import { loadKeepServicesPanel } from '~/store/keep-services/keep-services-actions';
import { loadUsersPanel, userBindedActions } from '~/store/users/users-actions';
+ import { loadLinkPanel, linkPanelActions } from '~/store/link-panel/link-panel-actions';
+ import { linkPanelColumns } from '~/views/link-panel/link-panel-root';
import { userPanelColumns } from '~/views/user-panel/user-panel';
import { loadComputeNodesPanel } from '~/store/compute-nodes/compute-nodes-actions';
import { loadApiClientAuthorizationsPanel } from '~/store/api-client-authorizations/api-client-authorizations-actions';
+import * as groupPanelActions from '~/store/groups-panel/groups-panel-actions';
+import { groupsPanelColumns } from '~/views/groups-panel/groups-panel';
+import * as groupDetailsPanelActions from '~/store/group-details-panel/group-details-panel-actions';
+import { groupDetailsPanelColumns } from '~/views/group-details-panel/group-details-panel';
export const WORKBENCH_LOADING_SCREEN = 'workbenchLoadingScreen';
dispatch(workflowPanelActions.SET_COLUMNS({ columns: workflowPanelColumns }));
dispatch(searchResultsPanelActions.SET_COLUMNS({ columns: searchResultsPanelColumns }));
dispatch(userBindedActions.SET_COLUMNS({ columns: userPanelColumns }));
+ dispatch(groupPanelActions.GroupsPanelActions.SET_COLUMNS({ columns: groupsPanelColumns }));
+ dispatch(groupDetailsPanelActions.GroupDetailsPanelActions.SET_COLUMNS({columns: groupDetailsPanelColumns}));
+ dispatch(linkPanelActions.SET_COLUMNS({ columns: linkPanelColumns }));
dispatch<any>(initSidePanelTree());
if (router.location) {
const match = matchRootRoute(router.location.pathname);
await dispatch(loadSearchResultsPanel());
});
+ export const loadLinks = handleFirstTimeLoad(
+ async (dispatch: Dispatch<any>) => {
+ await dispatch(loadLinkPanel());
+ });
+
export const loadVirtualMachines = handleFirstTimeLoad(
async (dispatch: Dispatch<any>) => {
await dispatch(loadVirtualMachinesPanel());
await dispatch(loadApiClientAuthorizationsPanel());
});
+export const loadGroupsPanel = handleFirstTimeLoad(
+ (dispatch: Dispatch<any>) => {
+ dispatch(setGroupsBreadcrumbs());
+ dispatch(groupPanelActions.loadGroupsPanel());
+ });
+
+
+export const loadGroupDetailsPanel = (groupUuid: string) =>
+ handleFirstTimeLoad(
+ (dispatch: Dispatch<any>) => {
+ dispatch(setGroupDetailsBreadcrumbs(groupUuid));
+ dispatch(groupDetailsPanelActions.loadGroupDetailsPanel(groupUuid));
+ });
+
const finishLoadingProject = (project: GroupContentsResource | string) =>
async (dispatch: Dispatch<any>) => {
const uuid = typeof project === 'string' ? project : project.uuid;
VIRTUAL_MACHINE = "VirtualMachine",
KEEP_SERVICE = "KeepService",
USER = "User",
- GROUP_MEMBER = "GroupMember"
+ NODE = "Node",
+ GROUPS = "Group",
- NODE = "Node"
++ GROUP_MEMBER = "GroupMember",
+ LINK = "Link",
}
import { RootState } from "~/store/store";
import { openCurrentTokenDialog } from '~/store/current-token-dialog/current-token-dialog-actions';
import { openRepositoriesPanel } from "~/store/repositories/repositories-actions";
- import {
- navigateToSshKeys, navigateToKeepServices, navigateToComputeNodes,
- navigateToApiClientAuthorizations, navigateToMyAccount, navigateToGroups
++import {
++ navigateToKeepServices, navigateToComputeNodes,
++ navigateToApiClientAuthorizations, navigateToGroups
+} from '~/store/navigation/navigation-action';
- import { openVirtualMachines } from "~/store/virtual-machines/virtual-machines-actions";
+import { navigateToUsers } from '~/store/navigation/navigation-action';
+ import { navigateToSshKeysUser, navigateToMyAccount } from '~/store/navigation/navigation-action';
+ import { openUserVirtualMachines } from "~/store/virtual-machines/virtual-machines-actions";
interface AccountMenuProps {
user?: User;
<MenuItem>
{getUserFullname(user)}
</MenuItem>
- <MenuItem onClick={() => dispatch(openVirtualMachines())}>Virtual Machines</MenuItem>
- <MenuItem onClick={() => dispatch(openRepositoriesPanel())}>Repositories</MenuItem>
+ <MenuItem onClick={() => dispatch(openUserVirtualMachines())}>Virtual Machines</MenuItem>
+ {!user.isAdmin && <MenuItem onClick={() => dispatch(openRepositoriesPanel())}>Repositories</MenuItem>}
<MenuItem onClick={() => dispatch(openCurrentTokenDialog)}>Current token</MenuItem>
- <MenuItem onClick={() => dispatch(navigateToSshKeys)}>Ssh Keys</MenuItem>
+ <MenuItem onClick={() => dispatch(navigateToUsers)}>Users</MenuItem>
- { user.isAdmin && <MenuItem onClick={() => dispatch(navigateToGroups)}>Groups</MenuItem> }
- { user.isAdmin && <MenuItem onClick={() => dispatch(navigateToApiClientAuthorizations)}>Api Tokens</MenuItem> }
- { user.isAdmin && <MenuItem onClick={() => dispatch(navigateToKeepServices)}>Keep Services</MenuItem> }
- { user.isAdmin && <MenuItem onClick={() => dispatch(navigateToComputeNodes)}>Compute Nodes</MenuItem> }
++ {user.isAdmin && <MenuItem onClick={() => dispatch(navigateToGroups)}>Groups</MenuItem>}
++ {user.isAdmin && <MenuItem onClick={() => dispatch(navigateToApiClientAuthorizations)}>Api Tokens</MenuItem>}
++ {user.isAdmin && <MenuItem onClick={() => dispatch(navigateToKeepServices)}>Keep Services</MenuItem>}
++ {user.isAdmin && <MenuItem onClick={() => dispatch(navigateToComputeNodes)}>Compute Nodes</MenuItem>}
+ <MenuItem onClick={() => dispatch(navigateToSshKeysUser)}>Ssh Keys</MenuItem>
<MenuItem onClick={() => dispatch(navigateToMyAccount)}>My account</MenuItem>
<MenuItem onClick={() => dispatch(logout())}>Logout</MenuItem>
</DropdownMenu>
import { SharingDialog } from '~/views-components/sharing-dialog/sharing-dialog';
import { AdvancedTabDialog } from '~/views-components/advanced-tab-dialog/advanced-tab-dialog';
import { ProcessInputDialog } from '~/views-components/process-input-dialog/process-input-dialog';
- import { VirtualMachinePanel } from '~/views/virtual-machine-panel/virtual-machine-panel';
+ import { VirtualMachineUserPanel } from '~/views/virtual-machine-panel/virtual-machine-user-panel';
+ import { VirtualMachineAdminPanel } from '~/views/virtual-machine-panel/virtual-machine-admin-panel';
import { ProjectPropertiesDialog } from '~/views-components/project-properties-dialog/project-properties-dialog';
import { RepositoriesPanel } from '~/views/repositories-panel/repositories-panel';
import { KeepServicePanel } from '~/views/keep-service-panel/keep-service-panel';
import { ComputeNodePanel } from '~/views/compute-node-panel/compute-node-panel';
import { ApiClientAuthorizationPanel } from '~/views/api-client-authorization-panel/api-client-authorization-panel';
+ import { LinkPanel } from '~/views/link-panel/link-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';
import { RemoveApiClientAuthorizationDialog } from '~/views-components/api-client-authorizations-dialog/remove-dialog';
import { RemoveComputeNodeDialog } from '~/views-components/compute-nodes-dialog/remove-dialog';
import { RemoveKeepServiceDialog } from '~/views-components/keep-services-dialog/remove-dialog';
+ import { RemoveLinkDialog } from '~/views-components/links-dialog/remove-dialog';
import { RemoveSshKeyDialog } from '~/views-components/ssh-keys-dialog/remove-dialog';
import { RemoveVirtualMachineDialog } from '~/views-components/virtual-machines-dialog/remove-dialog';
import { AttributesApiClientAuthorizationDialog } from '~/views-components/api-client-authorizations-dialog/attributes-dialog';
import { AttributesComputeNodeDialog } from '~/views-components/compute-nodes-dialog/attributes-dialog';
import { AttributesKeepServiceDialog } from '~/views-components/keep-services-dialog/attributes-dialog';
+ import { AttributesLinkDialog } from '~/views-components/links-dialog/attributes-dialog';
import { AttributesSshKeyDialog } from '~/views-components/ssh-keys-dialog/attributes-dialog';
import { VirtualMachineAttributesDialog } from '~/views-components/virtual-machines-dialog/attributes-dialog';
import { UserPanel } from '~/views/user-panel/user-panel';
import { UserAttributesDialog } from '~/views-components/user-dialog/attributes-dialog';
import { CreateUserDialog } from '~/views-components/dialog-forms/create-user-dialog';
import { HelpApiClientAuthorizationDialog } from '~/views-components/api-client-authorizations-dialog/help-dialog';
+import { GroupsPanel } from '~/views/groups-panel/groups-panel';
+import { CreateGroupDialog } from '~/views-components/dialog-forms/create-group-dialog';
+import { RemoveGroupDialog } from '~/views-components/groups-dialog/remove-dialog';
+import { GroupAttributesDialog } from '~/views-components/groups-dialog/attributes-dialog';
+import { GroupDetailsPanel } from '~/views/group-details-panel/group-details-panel';
+import { RemoveGroupMemberDialog } from '~/views-components/groups-dialog/member-remove-dialog';
+import { GroupMemberAttributesDialog } from '~/views-components/groups-dialog/member-attributes-dialog';
+import { AddGroupMembersDialog } from '~/views-components/dialog-forms/add-group-member-dialog';
type CssRules = 'root' | 'container' | 'splitter' | 'asidePanel' | 'contentWrapper' | 'content';
<Route path={Routes.RUN_PROCESS} component={RunProcessPanel} />
<Route path={Routes.WORKFLOWS} component={WorkflowPanel} />
<Route path={Routes.SEARCH_RESULTS} component={SearchResultsPanel} />
- <Route path={Routes.VIRTUAL_MACHINES} component={VirtualMachinePanel} />
+ <Route path={Routes.VIRTUAL_MACHINES_USER} component={VirtualMachineUserPanel} />
+ <Route path={Routes.VIRTUAL_MACHINES_ADMIN} component={VirtualMachineAdminPanel} />
<Route path={Routes.REPOSITORIES} component={RepositoriesPanel} />
- <Route path={Routes.SSH_KEYS} component={SshKeyPanel} />
+ <Route path={Routes.SSH_KEYS_USER} component={SshKeyPanel} />
+ <Route path={Routes.SSH_KEYS_ADMIN} component={SshKeyPanel} />
<Route path={Routes.KEEP_SERVICES} component={KeepServicePanel} />
<Route path={Routes.USERS} component={UserPanel} />
<Route path={Routes.COMPUTE_NODES} component={ComputeNodePanel} />
<Route path={Routes.API_CLIENT_AUTHORIZATIONS} component={ApiClientAuthorizationPanel} />
<Route path={Routes.MY_ACCOUNT} component={MyAccountPanel} />
+ <Route path={Routes.GROUPS} component={GroupsPanel} />
+ <Route path={Routes.GROUP_DETAILS} component={GroupDetailsPanel} />
+ <Route path={Routes.LINKS} component={LinkPanel} />
</Switch>
</Grid>
</Grid>
<Grid item>
<DetailsPanel />
</Grid>
+ <AddGroupMembersDialog />
<AdvancedTabDialog />
<AttributesApiClientAuthorizationDialog />
<AttributesComputeNodeDialog />
<AttributesKeepServiceDialog />
+ <AttributesLinkDialog />
<AttributesSshKeyDialog />
<ChangeWorkflowDialog />
<ContextMenu />
<CopyCollectionDialog />
<CopyProcessDialog />
<CreateCollectionDialog />
+ <CreateGroupDialog />
<CreateProjectDialog />
<CreateRepositoryDialog />
<CreateSshKeyDialog />
<CurrentTokenDialog />
<FileRemoveDialog />
<FilesUploadCollectionDialog />
+ <GroupAttributesDialog />
+ <GroupMemberAttributesDialog />
<HelpApiClientAuthorizationDialog />
<MoveCollectionDialog />
<MoveProcessDialog />
<ProjectPropertiesDialog />
<RemoveApiClientAuthorizationDialog />
<RemoveComputeNodeDialog />
+ <RemoveGroupDialog />
+ <RemoveGroupMemberDialog />
<RemoveKeepServiceDialog />
+ <RemoveLinkDialog />
<RemoveProcessDialog />
<RemoveRepositoryDialog />
<RemoveSshKeyDialog />