Skip to content

Commit

Permalink
Add workspace detail (#1746)
Browse files Browse the repository at this point in the history
* chore: bump component groups version

* feat: add translations for workspace detail

* chore: centralize per page values

* fix: fix displaying workspaces and add loading state

* feat: add workspace detail with tests

* fix: fix create workspace e2e
  • Loading branch information
fhlavac authored Jan 16, 2025
1 parent 186626a commit 0899d91
Show file tree
Hide file tree
Showing 25 changed files with 550 additions and 260 deletions.
6 changes: 3 additions & 3 deletions cypress/e2e/create-workspace.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ describe('Workspaces page', () => {
it('Displays create workspace button', () => {
cy.login();

cy.intercept('GET', '**/api/rbac/v2/workspaces/', {
cy.intercept('GET', '**/api/rbac/v2/workspaces/*', {
statusCode: 200,
body: { data: [], meta: {} },
}).as('getWorkspaces');
Expand All @@ -19,7 +19,7 @@ describe('Workspaces page', () => {
it('Opens the create workspace wizard', () => {
cy.login();

cy.intercept('GET', '**/api/rbac/v2/workspaces/', {
cy.intercept('GET', '**/api/rbac/v2/workspaces/*', {
statusCode: 200,
body: { data: [], meta: {} },
}).as('getWorkspaces');
Expand All @@ -39,7 +39,7 @@ describe('Workspaces page', () => {
it('Closes the create workspace wizard on cancel', () => {
cy.login();

cy.intercept('GET', '**/api/rbac/v2/workspaces/', {
cy.intercept('GET', '**/api/rbac/v2/workspaces/*', {
statusCode: 200,
body: { data: [], meta: {} },
}).as('getWorkspaces');
Expand Down
51 changes: 51 additions & 0 deletions cypress/e2e/workspaces-detail.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
describe('Workspaces page', () => {
const mockWorkspaces = {
meta: {
count: 1,
limit: 100,
offset: 0,
},
data: [
{
name: 'Root Workspace',
id: 'asd-sda-asd-dsa-asd',
parent_id: null,
description: null,
created: '2024-12-02T21:57:08.423927Z',
modified: '2024-12-02T21:57:08.504809Z',
type: 'root',
},
],
};

beforeEach(() => {
cy.login();

// mock the workspaces
cy.intercept('GET', '**/api/rbac/v2/workspaces/?limit=100', {
statusCode: 200,
body: mockWorkspaces,
}).as('getWorkspaces');

// mock the workspace
cy.intercept('GET', '**/api/rbac/v2/workspaces/asd-sda-asd-dsa-asd', {
statusCode: 200,
body: mockWorkspaces.data[0],
}).as('getWorkspace');
});

it('Visit Workspaces page', () => {
cy.visit('/iam/access-management/workspaces');
cy.wait('@getWorkspaces', { timeout: 30000 });

// check if Workspaces heading exists on the page
cy.contains('Workspaces').should('exist');

cy.contains('Root Workspace').click();

cy.wait('@getWorkspace', { timeout: 30000 });

cy.contains('Assets').should('be.visible');
cy.contains('Workspace hierarchy:').should('have.length', 1);
});
});
20 changes: 20 additions & 0 deletions locales/translation-template.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"accessOrigin": {
"defaultMessage": "Access origin",
"description": "Access origin modified column label"
},
"actionsOnClustersPermissions": {
"defaultMessage": "Only Org. Administrators and cluster owners can perform actions on clusters.",
"description": "Actions on clusters permissions message"
Expand Down Expand Up @@ -267,6 +271,10 @@
"defaultMessage": "Specify which workspaces you'd like to give access for these permissions",
"description": "Permissions for Workspaces"
},
"assets": {
"defaultMessage": "Assets",
"description": "Assets label"
},
"assignAtLeastOneGroup": {
"defaultMessage": "You need to assign at least one inventory group to each permission.",
"description": "Assign at least one inventory group message"
Expand Down Expand Up @@ -755,6 +763,10 @@
"defaultMessage": "Exit {item} creation?",
"description": "Exit item creation modal title"
},
"featuresManagement": {
"defaultMessage": "Features management",
"description": "Features management label"
},
"filterByKey": {
"defaultMessage": "Filter by {key}",
"description": "Filter by data key label"
Expand Down Expand Up @@ -1030,6 +1042,10 @@
"defaultMessage": "Name and description",
"description": "Name and description wizard step title"
},
"nameFilterPlaceholder": {
"defaultMessage": "Filter by name",
"description": "placeholder for name filter"
},
"no": {
"defaultMessage": "No",
"description": "No label"
Expand Down Expand Up @@ -1522,6 +1538,10 @@
"defaultMessage": "role",
"description": "Role singular"
},
"roleAssignments": {
"defaultMessage": "Role assignments",
"description": "Rola assignments label"
},
"roleCreatedSuccessfully": {
"defaultMessage": "You have successfully created a new role",
"description": "Role created successfully message"
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"@data-driven-forms/react-form-renderer": "^3.23.5",
"@formatjs/cli": "6.2.2",
"@patternfly/quickstarts": "^5.1.0",
"@patternfly/react-component-groups": "^5.5.6",
"@patternfly/react-component-groups": "^5.5.8",
"@patternfly/react-core": "^5.1.1",
"@patternfly/react-data-view": "^5.7.1",
"@patternfly/react-icons": "^5.1.1",
Expand Down
27 changes: 26 additions & 1 deletion src/Messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,11 @@ export default defineMessages({
description: 'Last modified column label',
defaultMessage: 'Last modified',
},
accessOrigin: {
id: 'accessOrigin',
description: 'Access origin modified column label',
defaultMessage: 'Access origin',
},
roleName: {
id: 'roleName',
description: 'Role name filter placeholder',
Expand Down Expand Up @@ -1053,6 +1058,21 @@ export default defineMessages({
description: 'Create workspace error notification description',
defaultMessage: 'The workspace was not created successfuly.',
},
roleAssignments: {
id: 'roleAssignments',
description: 'Rola assignments label',
defaultMessage: 'Role assignments',
},
assets: {
id: 'assets',
description: 'Assets label',
defaultMessage: 'Assets',
},
featuresManagement: {
id: 'featuresManagement',
description: 'Features management label',
defaultMessage: 'Features management',
},
workspace: {
id: 'workspace',
description: 'Workspace singular label',
Expand Down Expand Up @@ -1117,7 +1137,7 @@ export default defineMessages({
workspacesDetailBreadcrumbTitle: {
id: 'workspacesDetailBreadcrumbTitle',
description: 'Workspace detail breadcrumb title',
defaultMessage: 'Workspace hierarchy: ',
defaultMessage: 'Workspace hierarchy:',
},
createWorkspace: {
id: 'createWorkspace',
Expand Down Expand Up @@ -2431,6 +2451,11 @@ export default defineMessages({
description: 'Empty state subtitle Users',
defaultMessage: 'This filter criteria matches no users.{br}Try changing your filter input.',
},
roleAssignmentsEmptyStateSubtitle: {
id: 'roleAssignmentsEmptyStateSubtitle',
description: 'Empty state subtitle role bindings',
defaultMessage: 'This filter criteria matches no role assignments.{br}Try changing your filter input.',
},
userGroupsEmptyStateTitle: {
id: 'userGroupsEmptyStateTitle',
description: 'Empty state title User groups',
Expand Down
2 changes: 1 addition & 1 deletion src/Routing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const Overview = lazy(() => import('./smart-components/overview/overview'));
const WorkspacesOverview = lazy(() => import('./smart-components/workspaces/overview/about-access-tab'));
const WorkspaceList = lazy(() => import('./smart-components/workspaces/WorkspaceList'));
const CreateWorkspaceWizard = lazy(() => import('./smart-components/workspaces/create-workspace/CreateWorkspaceWizard'));
const WorkspaceDetail = lazy(() => import('./smart-components/workspaces/WorkspaceDetail'));
const WorkspaceDetail = lazy(() => import('./smart-components/workspaces/workspace-detail/WorkspaceDetail'));
const Users = lazy(() => import('./smart-components/user/users'));
const UserDetail = lazy(() => import('./smart-components/user/user'));
const AddUserToGroup = lazy(() => import('./smart-components/user/add-user-to-group/add-user-to-group'));
Expand Down
8 changes: 8 additions & 0 deletions src/helpers/shared/pagination.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ export const defaultCompactSettings = {
limit: 10,
};

export const PER_PAGE_OPTIONS = [
{ title: '5', value: 5 },
{ title: '10', value: 10 },
{ title: '20', value: 20 },
{ title: '50', value: 50 },
{ title: '100', value: 100 },
];

export const calculatePage = (limit = defaultSettings.limit, offset = 0) => Math.floor(offset / limit) + 1;

export const calculateOffset = (page = 1, limit = defaultSettings.limit) => (page - 1) * limit;
Expand Down
15 changes: 1 addition & 14 deletions src/helpers/workspaces/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,7 @@ axiosInstance.interceptors.response.use(null, errorInterceptor);
const workspacesApi = new APIFactory(
RBAC_API_BASE_2,
{
getWorkspace: async (...args) => {
const getWs = await getWorkspace(...args);
return {
...getWs,
options: {
...getWs.options,
transformResponse: () => {
return {
// TODO: return normal data
};
},
},
};
},
getWorkspace,
createWorkspace: async (...args) => {
const createWs = await createWorkspace(...args);
return {
Expand Down
9 changes: 5 additions & 4 deletions src/helpers/workspaces/workspaces-helper.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { WorkspacesListParams } from '@redhat-cloud-services/rbac-client/dist/v2/WorkspacesList';
import { WorkspaceCreateBody } from '../../redux/reducers/workspaces-reducer';
import { getWorkspacesApi } from './api';

const workspacesApi = getWorkspacesApi();

export async function getWorkspaces() {
return await workspacesApi.listWorkspaces();
export async function getWorkspaces(config: WorkspacesListParams = {}) {
return await workspacesApi.listWorkspaces({ limit: 100, ...config });
}

export async function getWorkspace(ws: string) {
return await workspacesApi.getWorkspace({ id: ws });
export async function getWorkspace(workspaceId: string) {
return await workspacesApi.getWorkspace(workspaceId);
}

export async function createWorkspace(config: WorkspaceCreateBody) {
Expand Down
5 changes: 5 additions & 0 deletions src/locales/data.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"en": {
"accessOrigin": "Access origin",
"actionsOnClustersPermissions": "Only Org. Administrators and cluster owners can perform actions on clusters.",
"activateUsersButton": "Activate users",
"active": "Active",
Expand Down Expand Up @@ -67,6 +68,7 @@
"applyCostPermissionText": "Specify where you would like to apply each cost permission selected in the previous step, using the dropdown below.",
"applyInventoryGroupsRolePermission": "Specify which inventory groups you'd like to give access for these permissions",
"applyWorkspacesRolePermission": "Specify which workspaces you'd like to give access for these permissions",
"assets": "Assets",
"assignAtLeastOneGroup": "You need to assign at least one inventory group to each permission.",
"assignAtLeastOneResource": "You need to assign at least one resource to each permission.",
"assignedRoles": "Assigned roles",
Expand Down Expand Up @@ -189,6 +191,7 @@
"exitEditResourceDefinitions": "Exit edit resource definitions?",
"exitItemAdding": "Exit {item} adding?",
"exitItemCreation": "Exit {item} creation?",
"featuresManagement": "Features management",
"filterByKey": "Filter by {key}",
"filterByResource": "Filter by resource...",
"filterMatchesNoFilters": "This filter criteria matches no {items}.",
Expand Down Expand Up @@ -258,6 +261,7 @@
"name": "Name",
"nameAlreadyTaken": "Name has already been taken.",
"nameAndDescription": "Name and description",
"nameFilterPlaceholder": "Filter by name",
"no": "No",
"noAccountsInDefaultAccess": "In adherence to security guidelines, service accounts are not automatically included in the default access group. To grant access, it is necessary to manually add them to the appropriate user access groups.",
"noAccountsInDefaultAdminAccess": "In adherence to security guidelines, service accounts are not automatically included in the default admin access group. To grant access, it is necessary to manually add them to the appropriate user access groups.",
Expand Down Expand Up @@ -381,6 +385,7 @@
"reviewRoleDetails": "Review and confirm the details for your role, or click Back to revise.",
"reviewWorkspaceDescription": "Review the information below to make sure everything is correct before creating a new workspace.",
"role": "role",
"roleAssignments": "Role assignments",
"roleCreatedSuccessfully": "You have successfully created a new role",
"roleDescription": "Role description",
"roleName": "Role name",
Expand Down
5 changes: 5 additions & 0 deletions src/locales/translations.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"accessOrigin": "Access origin",
"actionsOnClustersPermissions": "Only Org. Administrators and cluster owners can perform actions on clusters.",
"activateUsersButton": "Activate users",
"active": "Active",
Expand Down Expand Up @@ -66,6 +67,7 @@
"applyCostPermissionText": "Specify where you would like to apply each cost permission selected in the previous step, using the dropdown below.",
"applyInventoryGroupsRolePermission": "Specify which inventory groups you'd like to give access for these permissions",
"applyWorkspacesRolePermission": "Specify which workspaces you'd like to give access for these permissions",
"assets": "Assets",
"assignAtLeastOneGroup": "You need to assign at least one inventory group to each permission.",
"assignAtLeastOneResource": "You need to assign at least one resource to each permission.",
"assignedRoles": "Assigned roles",
Expand Down Expand Up @@ -188,6 +190,7 @@
"exitEditResourceDefinitions": "Exit edit resource definitions?",
"exitItemAdding": "Exit {item} adding?",
"exitItemCreation": "Exit {item} creation?",
"featuresManagement": "Features management",
"filterByKey": "Filter by {key}",
"filterByResource": "Filter by resource...",
"filterMatchesNoFilters": "This filter criteria matches no {items}.",
Expand Down Expand Up @@ -257,6 +260,7 @@
"name": "Name",
"nameAlreadyTaken": "Name has already been taken.",
"nameAndDescription": "Name and description",
"nameFilterPlaceholder": "Filter by name",
"no": "No",
"noAccountsInDefaultAccess": "In adherence to security guidelines, service accounts are not automatically included in the default access group. To grant access, it is necessary to manually add them to the appropriate user access groups.",
"noAccountsInDefaultAdminAccess": "In adherence to security guidelines, service accounts are not automatically included in the default admin access group. To grant access, it is necessary to manually add them to the appropriate user access groups.",
Expand Down Expand Up @@ -380,6 +384,7 @@
"reviewRoleDetails": "Review and confirm the details for your role, or click Back to revise.",
"reviewWorkspaceDescription": "Review the information below to make sure everything is correct before creating a new workspace.",
"role": "role",
"roleAssignments": "Role assignments",
"roleCreatedSuccessfully": "You have successfully created a new role",
"roleDescription": "Role description",
"roleName": "Role name",
Expand Down
10 changes: 2 additions & 8 deletions src/presentational-components/shared/toolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import PropTypes from 'prop-types';
import messages from '../../Messages';
import { pickBy } from 'lodash';
import { selectedRows, calculateChecked, debouncedFetch, firstUpperCase } from '../../helpers/shared/helpers';
import { calculateOffset, calculatePage, defaultSettings } from '../../helpers/shared/pagination';
import { calculateOffset, calculatePage, defaultSettings, PER_PAGE_OPTIONS } from '../../helpers/shared/pagination';

export const paginationBuilder = (pagination = {}, fetchData, filterValue = '', sortBy = '', paginationProps) => ({
...paginationProps,
Expand All @@ -20,13 +20,7 @@ export const paginationBuilder = (pagination = {}, fetchData, filterValue = '',
orderBy: sortBy,
});
},
perPageOptions: [
{ title: '5', value: 5 },
{ title: '10', value: 10 },
{ title: '20', value: 20 },
{ title: '50', value: 50 },
{ title: '100', value: 100 },
],
perPageOptions: PER_PAGE_OPTIONS,
onPerPageSelect: (_event, perPage) => {
fetchData({
offset: 0,
Expand Down
4 changes: 2 additions & 2 deletions src/redux/actions/workspaces-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ export const fetchWorkspaces = () => ({
payload: WorkspacesHelper.getWorkspaces(),
});

export const fetchWorkspace = (ws: string) => ({
export const fetchWorkspace = (workspaceId: string) => ({
type: ActionTypes.FETCH_WORKSPACE,
payload: WorkspacesHelper.getWorkspace(ws),
payload: WorkspacesHelper.getWorkspace(workspaceId),
});

export const createWorkspace = (config: WorkspaceCreateBody) => {
Expand Down
Loading

0 comments on commit 0899d91

Please sign in to comment.