feat: add team groups section in group configurations (#1728)
This commit is contained in:
committed by
GitHub
parent
c4a09a2b43
commit
e8cd7c2dcc
@@ -20,6 +20,7 @@ let store;
|
|||||||
const courseId = 'course-v1:org+101+101';
|
const courseId = 'course-v1:org+101+101';
|
||||||
const enrollmentTrackGroups = groupConfigurationResponseMock.allGroupConfigurations[0];
|
const enrollmentTrackGroups = groupConfigurationResponseMock.allGroupConfigurations[0];
|
||||||
const contentGroups = groupConfigurationResponseMock.allGroupConfigurations[1];
|
const contentGroups = groupConfigurationResponseMock.allGroupConfigurations[1];
|
||||||
|
const teamGroups = groupConfigurationResponseMock.allGroupConfigurations[2];
|
||||||
|
|
||||||
const renderComponent = () => render(
|
const renderComponent = () => render(
|
||||||
<CourseAuthoringProvider courseId={courseId}>
|
<CourseAuthoringProvider courseId={courseId}>
|
||||||
@@ -61,6 +62,7 @@ describe('<GroupConfigurations />', () => {
|
|||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
expect(getByText(contentGroups.name)).toBeInTheDocument();
|
expect(getByText(contentGroups.name)).toBeInTheDocument();
|
||||||
expect(getByText(enrollmentTrackGroups.name)).toBeInTheDocument();
|
expect(getByText(enrollmentTrackGroups.name)).toBeInTheDocument();
|
||||||
|
expect(getByText(teamGroups.name)).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ module.exports = {
|
|||||||
usage: null,
|
usage: null,
|
||||||
name: 'Enrollment Track Groups',
|
name: 'Enrollment Track Groups',
|
||||||
parameters: {
|
parameters: {
|
||||||
course_id: 'course-v1:org+101+101',
|
courseId: 'course-v1:org+101+101',
|
||||||
},
|
},
|
||||||
read_only: true,
|
readOnly: true,
|
||||||
scheme: 'enrollment_track',
|
scheme: 'enrollment_track',
|
||||||
version: 3,
|
version: 3,
|
||||||
},
|
},
|
||||||
@@ -68,6 +68,39 @@ module.exports = {
|
|||||||
scheme: 'cohort',
|
scheme: 'cohort',
|
||||||
version: 3,
|
version: 3,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
active: true,
|
||||||
|
description: 'Partition for segmenting users by team-set',
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
name: 'My Team 1',
|
||||||
|
usage: [],
|
||||||
|
version: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
name: 'My Team 2',
|
||||||
|
usage: [
|
||||||
|
{
|
||||||
|
label: 'Subsection / Unit',
|
||||||
|
url: '/container/block-v1:org+101+101+type@vertical+block@e960cb847be24b8c835ae1a0184d7831',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
version: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 92768376,
|
||||||
|
usage: null,
|
||||||
|
name: 'Team Group: My Group',
|
||||||
|
parameters: {
|
||||||
|
courseId: 'course-v1:org+101+101',
|
||||||
|
teamSetId: '0ec11208-335f-4b48-9475-136f02cc30f3"',
|
||||||
|
},
|
||||||
|
readOnly: true,
|
||||||
|
scheme: 'team',
|
||||||
|
version: 3,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
experimentGroupConfigurations: [
|
experimentGroupConfigurations: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,3 +2,4 @@ export { default as contentGroupsMock } from './contentGroupsMock';
|
|||||||
export { default as enrollmentTrackGroupsMock } from './enrollmentTrackGroupsMock';
|
export { default as enrollmentTrackGroupsMock } from './enrollmentTrackGroupsMock';
|
||||||
export { default as experimentGroupConfigurationsMock } from './experimentGroupConfigurationsMock';
|
export { default as experimentGroupConfigurationsMock } from './experimentGroupConfigurationsMock';
|
||||||
export { default as groupConfigurationResponseMock } from './groupConfigurationResponseMock';
|
export { default as groupConfigurationResponseMock } from './groupConfigurationResponseMock';
|
||||||
|
export { default as teamGroupsMock } from './teamGroupsMock';
|
||||||
|
|||||||
35
src/group-configurations/__mocks__/teamGroupsMock.ts
Normal file
35
src/group-configurations/__mocks__/teamGroupsMock.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { AvailableGroup } from '@src/group-configurations/types';
|
||||||
|
|
||||||
|
const teamGroupsMock: AvailableGroup = {
|
||||||
|
active: true,
|
||||||
|
description: 'Partition for segmenting users by team-set',
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
name: 'My Team 1',
|
||||||
|
usage: [],
|
||||||
|
version: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
name: 'My Team 2',
|
||||||
|
usage: [
|
||||||
|
{
|
||||||
|
label: 'Subsection / Unit',
|
||||||
|
url: '/container/block-v1:org+101+101+type@vertical+block@e960cb847be24b8c835ae1a0184d7831',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
version: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
id: 92768376,
|
||||||
|
name: 'Team Group: My Group',
|
||||||
|
parameters: {
|
||||||
|
courseId: 'course-v1:org+101+101',
|
||||||
|
},
|
||||||
|
readOnly: true,
|
||||||
|
scheme: 'team',
|
||||||
|
version: 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default teamGroupsMock;
|
||||||
@@ -12,6 +12,7 @@ import { SavingErrorAlert } from '../generic/saving-error-alert';
|
|||||||
import messages from './messages';
|
import messages from './messages';
|
||||||
import ContentGroupsSection from './content-groups-section';
|
import ContentGroupsSection from './content-groups-section';
|
||||||
import ExperimentConfigurationsSection from './experiment-configurations-section';
|
import ExperimentConfigurationsSection from './experiment-configurations-section';
|
||||||
|
import TeamGroupsSection from './team-groups-section';
|
||||||
import EnrollmentTrackGroupsSection from './enrollment-track-groups-section';
|
import EnrollmentTrackGroupsSection from './enrollment-track-groups-section';
|
||||||
import GroupConfigurationSidebar from './group-configuration-sidebar';
|
import GroupConfigurationSidebar from './group-configuration-sidebar';
|
||||||
import { useGroupConfigurations } from './hooks';
|
import { useGroupConfigurations } from './hooks';
|
||||||
@@ -59,9 +60,12 @@ const GroupConfigurations = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const enrollmentTrackGroup = shouldShowEnrollmentTrack
|
const enrollmentTrackGroup = shouldShowEnrollmentTrack
|
||||||
? allGroupConfigurations[0]
|
? allGroupConfigurations.find((group) => group.scheme === 'enrollment_track')
|
||||||
: null;
|
: null;
|
||||||
const contentGroup = allGroupConfigurations?.[shouldShowEnrollmentTrack ? 1 : 0];
|
|
||||||
|
const contentGroup = allGroupConfigurations.find((group) => group.scheme === 'cohort');
|
||||||
|
|
||||||
|
const teamGroups = allGroupConfigurations.filter((group) => group.scheme === 'team');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -83,6 +87,13 @@ const GroupConfigurations = () => {
|
|||||||
gap={3}
|
gap={3}
|
||||||
data-testid="group-configurations-main-content-wrapper"
|
data-testid="group-configurations-main-content-wrapper"
|
||||||
>
|
>
|
||||||
|
{!!teamGroups && teamGroups.length > 0 && (
|
||||||
|
teamGroups.map((teamGroup) => (
|
||||||
|
<TeamGroupsSection
|
||||||
|
availableGroup={teamGroup}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
)}
|
||||||
{!!enrollmentTrackGroup && (
|
{!!enrollmentTrackGroup && (
|
||||||
<EnrollmentTrackGroupsSection
|
<EnrollmentTrackGroupsSection
|
||||||
availableGroup={enrollmentTrackGroup}
|
availableGroup={enrollmentTrackGroup}
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { initializeMocks, render } from '@src/testUtils';
|
||||||
|
import { teamGroupsMock } from '@src/group-configurations/__mocks__';
|
||||||
|
import TeamGroupsSection from '.';
|
||||||
|
|
||||||
|
const renderComponent = (
|
||||||
|
props: Partial<React.ComponentProps<typeof TeamGroupsSection>> = {},
|
||||||
|
) => {
|
||||||
|
initializeMocks();
|
||||||
|
return render(
|
||||||
|
<TeamGroupsSection
|
||||||
|
availableGroup={teamGroupsMock}
|
||||||
|
{...props}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('<TeamGroupsSection />', () => {
|
||||||
|
it('renders component correctly', () => {
|
||||||
|
const { getByText, getAllByTestId } = renderComponent();
|
||||||
|
|
||||||
|
expect(getByText(teamGroupsMock.name)).toBeInTheDocument();
|
||||||
|
expect(getAllByTestId('content-group-card')).toHaveLength(
|
||||||
|
teamGroupsMock.groups.length,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders the team group name as a heading', () => {
|
||||||
|
const { getByRole } = renderComponent();
|
||||||
|
|
||||||
|
const heading = getByRole('heading', { name: teamGroupsMock.name });
|
||||||
|
expect(heading).toBeInTheDocument();
|
||||||
|
expect(heading).toHaveClass('configuration-section-name');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders all team groups from the availableGroup prop', () => {
|
||||||
|
const { getByText } = renderComponent();
|
||||||
|
|
||||||
|
teamGroupsMock.groups.forEach((group) => {
|
||||||
|
expect(getByText(group.name)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders content group cards as read-only', () => {
|
||||||
|
const { getAllByTestId } = renderComponent();
|
||||||
|
|
||||||
|
const cards = getAllByTestId('content-group-card');
|
||||||
|
expect(cards).toHaveLength(teamGroupsMock.groups.length);
|
||||||
|
|
||||||
|
// Verify that no edit or delete buttons are present (read-only mode)
|
||||||
|
const editButtons = document.querySelectorAll('[data-testid="content-group-card-header-edit"]');
|
||||||
|
const deleteButtons = document.querySelectorAll('[data-testid="content-group-card-header-delete"]');
|
||||||
|
|
||||||
|
expect(editButtons).toHaveLength(0);
|
||||||
|
expect(deleteButtons).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders with custom availableGroup prop', () => {
|
||||||
|
const customGroup = {
|
||||||
|
...teamGroupsMock,
|
||||||
|
name: 'Custom Team Group',
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
id: 100,
|
||||||
|
name: 'Custom Team 1',
|
||||||
|
usage: [],
|
||||||
|
version: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const { getByText, getAllByTestId } = renderComponent({
|
||||||
|
availableGroup: customGroup,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(getByText('Custom Team Group')).toBeInTheDocument();
|
||||||
|
expect(getByText('Custom Team 1')).toBeInTheDocument();
|
||||||
|
expect(getAllByTestId('content-group-card')).toHaveLength(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
25
src/group-configurations/team-groups-section/index.tsx
Normal file
25
src/group-configurations/team-groups-section/index.tsx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { AvailableGroup } from '@src/group-configurations/types';
|
||||||
|
import ContentGroupCard from '@src/group-configurations/content-groups-section/ContentGroupCard';
|
||||||
|
|
||||||
|
interface TeamGroupsSectionProps {
|
||||||
|
availableGroup: AvailableGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TeamGroupsSection: React.FC<TeamGroupsSectionProps> = ({
|
||||||
|
availableGroup: { groups, name },
|
||||||
|
}) => (
|
||||||
|
<div className="mt-2.5">
|
||||||
|
<h2 className="lead text-black mb-3 configuration-section-name">{name}</h2>
|
||||||
|
{groups.map((group) => (
|
||||||
|
<ContentGroupCard
|
||||||
|
group={group}
|
||||||
|
key={group.id}
|
||||||
|
readOnly
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default TeamGroupsSection;
|
||||||
27
src/group-configurations/types.ts
Normal file
27
src/group-configurations/types.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
export interface Usage {
|
||||||
|
label: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Group {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
usage: Usage[];
|
||||||
|
version: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AvailableGroupParameters {
|
||||||
|
courseId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AvailableGroup {
|
||||||
|
active?: boolean;
|
||||||
|
description?: string;
|
||||||
|
groups: Group[];
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
parameters?: AvailableGroupParameters;
|
||||||
|
readOnly?: boolean;
|
||||||
|
scheme: string;
|
||||||
|
version: number;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user