Skip to content

Commit 195249e

Browse files
authored
feat: Legacy libraries migration help sidebar [FC-0097] (#2503)
- Implements the Legacy Libraries Migration Help Sidebar - Shows the sidebar in the studio home - Shows the sidebar in the Legacy Libraries Migration Page
1 parent 4a26a86 commit 195249e

5 files changed

Lines changed: 223 additions & 74 deletions

File tree

src/legacy-libraries-migration/LegacyLibMigrationPage.test.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,9 @@ describe('<LegacyLibMigrationPage />', () => {
5353
// Should render the title
5454
expect(await screen.findByText('Migrate Legacy Libraries')).toBeInTheDocument();
5555
// Should render the Migration Steps Viewer
56-
expect(screen.getByText(/select legacy libraries/i)).toBeInTheDocument();
57-
expect(screen.getByText(/select destination/i)).toBeInTheDocument();
58-
expect(screen.getByText(/confirm/i)).toBeInTheDocument();
56+
expect(screen.getByText('Select Legacy Libraries')).toBeInTheDocument();
57+
expect(screen.getByText('Select Destination')).toBeInTheDocument();
58+
expect(screen.getByText('Confirm')).toBeInTheDocument();
5959
});
6060

6161
it('should cancel the migration', async () => {
@@ -401,4 +401,12 @@ describe('<LegacyLibMigrationPage />', () => {
401401
);
402402
expect(mockShowToast).toHaveBeenCalledWith('Legacy libraries migration failed.');
403403
});
404+
405+
it('should show help sidebar', async () => {
406+
renderPage();
407+
expect(await screen.findByText('Help & Support')).toBeInTheDocument();
408+
expect(screen.getByText('What’s different in the new Content Libraries experience?')).toBeInTheDocument();
409+
expect(screen.getByText('What happens when I migrate my Legacy Libraries?')).toBeInTheDocument();
410+
expect(screen.getByText('How do I migrate my Legacy Libraries?')).toBeInTheDocument();
411+
});
404412
});

src/legacy-libraries-migration/LegacyLibMigrationPage.tsx

Lines changed: 83 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
ActionRow,
1313
Button,
1414
Container,
15+
Layout,
1516
ModalDialog,
1617
StatefulButton,
1718
Stepper,
@@ -27,6 +28,7 @@ import { Filter, LibrariesList } from '@src/studio-home/tabs-section/libraries-t
2728
import messages from './messages';
2829
import { SelectDestinationView } from './SelectDestinationView';
2930
import { ConfirmationView } from './ConfirmationView';
31+
import { LegacyMigrationHelpSidebar } from './LegacyMigrationHelpSidebar';
3032
import { useUpdateContainerCollections } from './data/apiHooks';
3133

3234
export type MigrationStep = 'select-libraries' | 'select-destination' | 'confirmation-view';
@@ -164,79 +166,90 @@ export const LegacyLibMigrationPage = () => {
164166

165167
return (
166168
<>
169+
<Helmet>
170+
<title>
171+
{intl.formatMessage(messages.siteTitle)}
172+
</title>
173+
</Helmet>
174+
<Header isHiddenMainMenu />
167175
<div className="legacy-library-migration-page">
168-
<Helmet>
169-
<title>
170-
{intl.formatMessage(messages.siteTitle)}
171-
</title>
172-
</Helmet>
173-
<Header isHiddenMainMenu />
174-
<Container className="migration-container d-flex flex-column px-6 mt-5 mb-5">
175-
<div className="migration-content">
176-
<SubHeader
177-
title={intl.formatMessage(messages.siteTitle)}
178-
/>
179-
<Stepper activeKey={currentStep}>
180-
<Stepper.Header />
181-
<Stepper.Step
182-
eventKey="select-libraries"
183-
title={intl.formatMessage(messages.selectLegacyLibrariesStepTitle)}
184-
>
185-
<LibrariesList
186-
selectedIds={legacyLibrariesIds}
187-
handleCheck={handleUpdateLegacyLibraries}
188-
hideMigationAlert
189-
initialFilter={[Filter.unmigrated]}
190-
setSelectedLibraries={setLegacyLibraries}
191-
/>
192-
</Stepper.Step>
193-
<Stepper.Step
194-
eventKey="select-destination"
195-
title={intl.formatMessage(messages.selectDestinationStepTitle)}
196-
>
197-
<SelectDestinationView
198-
destinationId={destinationLibrary?.id}
199-
setDestinationId={setDestination}
200-
legacyLibCount={legacyLibraries.length}
201-
/>
202-
</Stepper.Step>
203-
<Stepper.Step
204-
eventKey="confirmation-view"
205-
title={intl.formatMessage(messages.confirmStepTitle)}
206-
>
207-
{destinationLibrary && (
208-
<ConfirmationView
209-
destination={destinationLibrary}
210-
legacyLibraries={legacyLibraries}
176+
<Layout
177+
xs={[{ span: 9 }, { span: 3 }]}
178+
>
179+
<Layout.Element>
180+
<div className="flex-fill">
181+
<Container className="migration-container d-flex flex-column px-6 mt-5 mb-5">
182+
<div className="migration-content">
183+
<SubHeader
184+
title={intl.formatMessage(messages.siteTitle)}
185+
/>
186+
<Stepper activeKey={currentStep}>
187+
<Stepper.Header />
188+
<Stepper.Step
189+
eventKey="select-libraries"
190+
title={intl.formatMessage(messages.selectLegacyLibrariesStepTitle)}
191+
>
192+
<LibrariesList
193+
selectedIds={legacyLibrariesIds}
194+
handleCheck={handleUpdateLegacyLibraries}
195+
hideMigationAlert
196+
initialFilter={[Filter.unmigrated]}
197+
setSelectedLibraries={setLegacyLibraries}
198+
/>
199+
</Stepper.Step>
200+
<Stepper.Step
201+
eventKey="select-destination"
202+
title={intl.formatMessage(messages.selectDestinationStepTitle)}
203+
>
204+
<SelectDestinationView
205+
destinationId={destinationLibrary?.id}
206+
setDestinationId={setDestination}
207+
legacyLibCount={legacyLibraries.length}
208+
/>
209+
</Stepper.Step>
210+
<Stepper.Step
211+
eventKey="confirmation-view"
212+
title={intl.formatMessage(messages.confirmStepTitle)}
213+
>
214+
{destinationLibrary && (
215+
<ConfirmationView
216+
destination={destinationLibrary}
217+
legacyLibraries={legacyLibraries}
218+
/>
219+
)}
220+
</Stepper.Step>
221+
</Stepper>
222+
</div>
223+
</Container>
224+
<div className="content-buttons d-flex justify-content-between pl-6 pr-6 bg-white">
225+
<Button className="mt-2 mb-2" variant="outline-primary" onClick={handleBack}>
226+
{currentStep === 'select-libraries'
227+
? intl.formatMessage(messages.cancel)
228+
: intl.formatMessage(messages.back)}
229+
</Button>
230+
{currentStep !== 'confirmation-view' ? (
231+
<Button className="mt-2 mb-2" onClick={handleNext} disabled={isNextDisabled()}>
232+
{intl.formatMessage(messages.next)}
233+
</Button>
234+
) : (
235+
<StatefulButton
236+
className="mt-2 mb-2"
237+
state={confirmationButtonState}
238+
disabledStates={['pending']}
239+
labels={{
240+
default: intl.formatMessage(messages.confirm),
241+
pending: intl.formatMessage(messages.confirm),
242+
}}
243+
onClick={handleNext}
211244
/>
212245
)}
213-
</Stepper.Step>
214-
</Stepper>
215-
</div>
216-
</Container>
217-
<div className="content-buttons d-flex justify-content-between pl-6 pr-6 bg-white">
218-
<Button className="mt-2 mb-2" variant="outline-primary" onClick={handleBack}>
219-
{currentStep === 'select-libraries'
220-
? intl.formatMessage(messages.cancel)
221-
: intl.formatMessage(messages.back)}
222-
</Button>
223-
{currentStep !== 'confirmation-view' ? (
224-
<Button className="mt-2 mb-2" onClick={handleNext} disabled={isNextDisabled()}>
225-
{intl.formatMessage(messages.next)}
226-
</Button>
227-
) : (
228-
<StatefulButton
229-
className="mt-2 mb-2"
230-
state={confirmationButtonState}
231-
disabledStates={['pending']}
232-
labels={{
233-
default: intl.formatMessage(messages.confirm),
234-
pending: intl.formatMessage(messages.confirm),
235-
}}
236-
onClick={handleNext}
237-
/>
238-
)}
239-
</div>
246+
</div>
247+
</div>
248+
</Layout.Element>
249+
<Layout.Element>
250+
<LegacyMigrationHelpSidebar />
251+
</Layout.Element>
252+
</Layout>
240253
</div>
241254
<ExitModal
242255
isExitModalOpen={isExitModalOpen}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { FormattedMessage } from '@edx/frontend-platform/i18n';
2+
import { Icon, Stack } from '@openedx/paragon';
3+
import { Question } from '@openedx/paragon/icons';
4+
5+
import messages from './messages';
6+
7+
export const SingleLineBreak = (chunk: string[]) => <div>{chunk}</div>;
8+
export const Paragraph = (chunk: string[]) => <p>{chunk}</p>;
9+
10+
export const LegacyMigrationHelpSidebar = () => (
11+
<div className="legacy-libraries-migration-help bg-white pt-3 mt-1">
12+
<Stack gap={1} direction="horizontal" className="pl-4 h4 text-primary-700">
13+
<Icon src={Question} />
14+
<span>
15+
<FormattedMessage {...messages.helpAndSupportTitle} />
16+
</span>
17+
</Stack>
18+
<hr />
19+
<Stack className="pl-4 pr-4">
20+
<Stack>
21+
<span className="h5">
22+
<FormattedMessage {...messages.helpAndSupportFirstQuestionTitle} />
23+
</span>
24+
<span className="x-small">
25+
<FormattedMessage {...messages.helpAndSupportFirstQuestionBody} />
26+
</span>
27+
</Stack>
28+
<hr />
29+
<Stack>
30+
<span className="h5">
31+
<FormattedMessage {...messages.helpAndSupportSecondQuestionTitle} />
32+
</span>
33+
<span className="x-small">
34+
<FormattedMessage {...messages.helpAndSupportSecondQuestionBody} />
35+
</span>
36+
</Stack>
37+
<hr />
38+
<Stack>
39+
<span className="h5">
40+
<FormattedMessage {...messages.helpAndSupportThirdQuestionTitle} />
41+
</span>
42+
<span className="x-small">
43+
<FormattedMessage
44+
{...messages.helpAndSupportThirdQuestionBody}
45+
values={{ div: SingleLineBreak, p: Paragraph }}
46+
/>
47+
</span>
48+
</Stack>
49+
</Stack>
50+
</div>
51+
);

src/legacy-libraries-migration/index.scss

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
.legacy-library-migration-page {
22
.migration-container {
3+
// Calculate all the screen size subtracting the height of the header and top/bottom margins
4+
min-height: calc(calc(100vh - 60px) - calc(var(--pgn-spacing-spacer-base) * 6));
5+
36
.courses-tab-container {
47
min-height: auto;
58
}
@@ -25,7 +28,29 @@
2528

2629
.content-buttons {
2730
width: 100%;
28-
position: fixed;
31+
position: sticky;
2932
bottom: 0;
3033
}
34+
35+
.row {
36+
margin-right: 0; // To avoid create a horizontal scroll using Layout
37+
}
38+
39+
[class*="col-"] {
40+
// To avoid create an empty gray space between the main content and the sidebar
41+
padding-right: 0;
42+
padding-left: 0;
43+
}
44+
}
45+
46+
.legacy-libraries-migration-help {
47+
z-index: 1000; // same as header
48+
flex: 350px 0 0;
49+
position: sticky;
50+
top: 0;
51+
right: 0;
52+
53+
hr {
54+
width: 100%;
55+
}
3156
}

src/legacy-libraries-migration/messages.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,58 @@ const messages = defineMessages({
8282
+ ' moved will be migrated to <b>{libraryName}</b>',
8383
description: 'Alert text when the legacy library is already migrated.',
8484
},
85+
helpAndSupportTitle: {
86+
id: 'legacy-libraries-migration.helpAndSupport.title',
87+
defaultMessage: 'Help & Support',
88+
description: 'Title of the Help & Support sidebar',
89+
},
90+
helpAndSupportFirstQuestionTitle: {
91+
id: 'legacy-libraries-migration.helpAndSupport.q1.title',
92+
defaultMessage: 'What’s different in the new Content Libraries experience?',
93+
description: 'Title of the first question in the Help & Support sidebar',
94+
},
95+
helpAndSupportFirstQuestionBody: {
96+
id: 'legacy-libraries-migration.helpAndSupport.q1.body',
97+
defaultMessage: 'In the new Content Libraries experience, you can author sections,'
98+
+ ' subsections, units, and many types of components. Library content can be reused across many courses,'
99+
+ ' and kept up-to-date. Content libraries now support increased collaboration across authoring teams.',
100+
description: 'Body of the first question in the Help & Support sidebar',
101+
},
102+
helpAndSupportSecondQuestionTitle: {
103+
id: 'legacy-libraries-migration.helpAndSupport.q2.title',
104+
defaultMessage: 'What happens when I migrate my Legacy Libraries?',
105+
description: 'Title of the second question in the Help & Support sidebar',
106+
},
107+
helpAndSupportSecondQuestionBody: {
108+
id: 'legacy-libraries-migration.helpAndSupport.q2.body',
109+
defaultMessage: 'All legacy library content is supported in the new experience.'
110+
+ ' Content from legacy libraries will be migrated to its own collection in the new Content Libraries experience.'
111+
+ ' This collection will have the same name as your original library. Courses that use legacy library content will'
112+
+ ' continue to function as usual, linked to the migrated version within the new libraries experience.',
113+
description: 'Body of the second question in the Help & Support sidebar',
114+
},
115+
helpAndSupportThirdQuestionTitle: {
116+
id: 'legacy-libraries-migration.helpAndSupport.q3.title',
117+
defaultMessage: 'How do I migrate my Legacy Libraries?',
118+
description: 'Title of the third question in the Help & Support sidebar',
119+
},
120+
helpAndSupportThirdQuestionBody: {
121+
id: 'legacy-libraries-migration.helpAndSupport.q3.body.2',
122+
defaultMessage: '<p>There are three steps to migrating legacy libraries:</p>'
123+
+ '<p><div>1 - Select Legacy Libraries</div>'
124+
+ 'You can select up to 50 legacy libraries for migration in this step. By default, only libraries that have'
125+
+ ' not yet been migrated are shown. To see all libraries, remove the filter.'
126+
+ ' You can select up to 50 legacy libraries for migration, but only one destination'
127+
+ ' v2 Content Library per migration.</p>'
128+
+ '<p><div>2 - Select Destination</div>'
129+
+ 'You can migrate legacy libraries to an existing Content Library in the new experience,'
130+
+ ' or you can create a new destination. You can only select one v2 Content Library per migration.'
131+
+ ' All your content will be migrated, and kept organized in collections.</p>'
132+
+ '<p><div>3 - Confirm</div>'
133+
+ 'In this step, review your migration. Once you confirm, migration will begin.'
134+
+ ' It may take some time to complete.</p>',
135+
description: 'Part 2 of the Body of the third question in the Help & Support sidebar',
136+
},
85137
migrationInProgress: {
86138
id: 'legacy-libraries-migration.confirmation-step.toast.migration-in-progress',
87139
defaultMessage: '{count, plural, one {{count} legacy library is} other {{count} legacy libraries are}} being migrated.',

0 commit comments

Comments
 (0)